设计模式【二】:构造器
伪代码
//定义一个自定义集合的构造器
class setBuilder{
public:
virtual void buildSet(){}
virtual void buildA(int a){}
virtual void buildB(int b){}
virtual mySet* getSet(){return 0;}
protected:
setBuilder();
};
//定义使用构造器的方法
mySet* createMySet(setBuilder& builder){
builder.buildSet();
builder.buildA(114);
builder.buildB(514);
return builder.getSet();
}
//实例化构造器
class standardSetBuilder: public setBuilder{
public:
standardSetBuilder(){currSet=0;}
void buildSet(){currSet=new currSet;}
void buildA(int a){currSet.A = a;}
void buildB(int b){currSet.B = b;}
mySet* getSet(){return currSet;}
private:
mySet* currSet;
}
//使用构造器
mySet* result = createMySet(standardSetBuilder);
//现在需要更改一些构造器的细节
class plusSetBuilder: public setBuilder{
public:
standardSetBuilder(){currSet=0;}
void buildSet(){currSet=new currSet;}
void buildA(int a){currSet.A = a+1;}
void buildB(int b){currSet.B = b+1;}
mySet* getSet(){return currSet;}
private:
mySet* currSet;
}
//调用过程不变
mySet* result1 = createMySet(minusSetBuilder);
优缺点
优点
- 可更改产品的内部表现
构造器只提供一个构造的接口,具体怎么构造需要在实体类中实现。比如伪代码中buildA()这个方法,我可以让产品中的a等于输入,也可以让它等于输入减一或加一。这一切对于调用者来说都是隐藏的:我不知道最后a是什么,我只知道我要在产品中加一个a就行了。 - 隔离代码的构造部分与显示部分
构造器把复杂对象的构造过程和它之后的使用等等隔离。使用对象的代码不知道这个对象的定义是什么,内部结构如何。每个实体化的构造器包括构造产品的所有方法,这里的方法是给这个产品添加一个部件,但调用者不知道具体如何添加。 - 更方便控制产品的构造过程
我们当然可以在类的构造方法中实现全部细节,然后在创建类的时候一次性生成此类,不过通过构造器我们可以一步步创建这个类,并在我们认为创建完毕的时候把这个类从构造器中取出来,例如伪代码中的getSet()方法。总之,这个过程更容易被我们控制。
缺点
没什么缺点。如果有的话,那便是采用设计模式的通常缺陷:一定程度上牺牲了代码的简洁性。
何时使用
- 创建复杂对象的代码和构建复杂对象的代码独立。二者之间是有区别的:比如创建对象的代码是盖一间毛坯房,构建的代码是为毛坯房装修。
- 构建对象的过程允许最终的对象有不同的结构。比如我这个房间可能一扇门也可能两扇门,这时调用一次或两次addDoor()即可。
实现时技巧
- 有一个抽象类提供接口,实体的构造器继承并实现抽象类。
- 构造器需要提供足够多的接口以满足调用者的构造需求。
- 有时我们需要特别灵活的产品构型,此时与其创建产品的抽象类然后继承,不如采用构造器。因为产品的抽象类不足以应付特别灵活的产品构型,接口可能不够泛用。