构造器模式,将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
通俗的话来讲,就是把成员变量的初始化与构造函数进行分离。
考虑到当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,有些参数需要she'zhi考虑使用构造者模式。
解决的问题
当一个类的构造函数参数超过4个,而且这些参数有些是可选的时,我们通常有两种办法来构建它的对象。 例如我们现在有如下一个类计算机类Computer
,其中cpu与ram是必填参数,而其他3个是可选参数,那么我们如何构造这个类的实例呢,通常有两种常用的方式:
第一:折叠构造函数模式(telescoping constructor pattern )
class Computer {
string cpu;//必须
string ram;//必须
int usbCount;//可选
string keyboard;//可选
string display;//可选
public:
Computer(string cpu, string ram) {
this(cpu, ram, 0);
}
Computer(string cpu, string ram, int usbCount) {
this(cpu, ram, usbCount, "罗技键盘");
}
Computer(string cpu, string ram, int usbCount, string keyboard) {
this(cpu, ram, usbCount, keyboard, "三星显示器");
}
Computer(string cpu, string ram, int usbCount, string keyboard, string display) {
this->cpu = cpu;
this->ram = ram;
this->usbCount = usbCount;
this->keyboard = keyboard;
this->display = display;
}
}
虽然,在C++语言中,可以在形参中赋默认值,但是在其他语言中,上面的表达方式弊端就十分的明显,阅读起来不方便,操作起来也不方便,当构造函数参数超过10个以上时,你在穿参初始化时很容易把值传错给其他的参数。所以builder模式就产生了
一、优化的builder模式:
两个主要的实现思路,将必须初始化的数据设置成构造函数,且构造函数不能太长,将可选的成员变量另外去赋值。
#include "iostream"
using namespace std;
class Computer {
private:
Computer() {
}
string cpu;//必须
string ram;//必须
int usbCount;//可选
string keyboard;//可选
string display;//可选
public:
class Builder{
string cpu;//必须
string ram;//必须
int usbCount;//可选
string keyboard;//可选
string display;//可选
public:
Builder(string cup,string ram){
this->cpu=cup;
this->ram=ram;
}
const string &getCpu() const {
return cpu;
}
const string &getRam() const {
return ram;
}
int getUsbCount() const {
return usbCount;
}
const string &getKeyboard() const {
return keyboard;
}
const string &getDisplay() const {
return display;
}
Builder& setUsbCount(int usbCount) {
this->usbCount = usbCount;
return *this;
}
Builder& setKeyboard(string keyboard) {
this->keyboard = keyboard;
return *this;
}
Builder& setDisplay(string display) {
this->display = display;
return *this;
}
Computer * build(){
return new Computer(*this);
}
};
//省略getter方法
Computer(Builder builder){
this->cpu=builder.getCpu();
this->ram=builder.getRam();
this->usbCount=builder.getUsbCount();
this->keyboard=builder.getKeyboard();
this->display=builder.getDisplay();
}
};
int main(){
Computer * computerPtr = Computer::Builder("因特尔","三星")
.setDisplay("三星24寸")
.setKeyboard("罗技")
.setUsbCount(2).build();
return 0;
}
优化的builder省去了Director角色,而把Builder嵌套在实体类中,充当一个内部类。
二、传统Builder 模式
最原先的builder 模式有一个director类,
1.在builder抽象类中,将实体类Product的可选成员参数的赋值设置为抽象函数,必选成员变量设置为Product实体类和 Builder派生类的构造函数。
2.Procuct 为 Builder派生类 的子对象
3.director 负责初始化 Builder。
1) 定义实体类
public class Computer {
private String cpu;//必须
private String ram;//必须
private int usbCount;//可选
private String keyboard;//可选
private String display;//可选
public Computer(String cpu, String ram) {
this.cpu = cpu;
this.ram = ram;
}
public void setUsbCount(int usbCount) {
this.usbCount = usbCount;
}
public void setKeyboard(String keyboard) {
this.keyboard = keyboard;
}
public void setDisplay(String display) {
this.display = display;
}
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", ram='" + ram + '\'' +
", usbCount=" + usbCount +
", keyboard='" + keyboard + '\'' +
", display='" + display + '\'' +
'}';
}
}
2)抽象Builder类 和 派生类
public abstract class ComputerBuilder {
public abstract void setUsbCount();
public abstract void setKeyboard();
public abstract void setDisplay();
public abstract Computer getComputer();
}
//苹果电脑构建者
public class MacComputerBuilder extends ComputerBuilder {
private Computer computer;
public MacComputerBuilder(String cpu, String ram) {
computer = new Computer(cpu, ram);
}
@Override
public void setUsbCount() {
computer.setUsbCount(2);
}
@Override
public void setKeyboard() {
computer.setKeyboard("苹果键盘");
}
@Override
public void setDisplay() {
computer.setDisplay("苹果显示器");
}
@Override
public Computer getComputer() {
return computer;
}
}
//联想电脑构建者类
public class LenovoComputerBuilder extends ComputerBuilder {
private Computer computer;
public LenovoComputerBuilder(String cpu, String ram) {
computer=new Computer(cpu,ram);
}
@Override
public void setUsbCount() {
computer.setUsbCount(4);
}
@Override
public void setKeyboard() {
computer.setKeyboard("联想键盘");
}
@Override
public void setDisplay() {
computer.setDisplay("联想显示器");
}
@Override
public Computer getComputer() {
return computer;
}
}
3) director 类
public class ComputerDirector {
public void makeComputer(ComputerBuilder builder){
builder.setUsbCount();
builder.setDisplay();
builder.setKeyboard();
}
}
使用案例:
public static void main(String[] args) {
ComputerDirector director=new ComputerDirector();//1
ComputerBuilder builder=new MacComputerBuilder("I5处理器","三星125");//2
director.makeComputer(builder);//3
Computer macComputer=builder.getComputer();//4
System.out.println("mac computer:"+macComputer.toString());
ComputerBuilder lenovoBuilder=new LenovoComputerBuilder("I7处理器","海力士222");
director.makeComputer(lenovoBuilder);
Computer lenovoComputer=lenovoBuilder.getComputer();
System.out.println("lenovo computer:"+lenovoComputer.toString());
}