builder模式,即建造者模式,和前面的工厂一样都是用于解决对象创建的问题。
意图:
将一个复杂对象的构建与它的实现分离,使得同样的构建过程可以创建不同的表示。
问题抛出,什么是复杂对象的构建过程。
代码:
class Car { public: void Init() //构造 { this->designPrototype(); for (int i = 0; i < 4; i++) { this->wheelInstall(i); } this->smartInit(); this->systemTest(); } protected: virtual void designPrototype()=0; virtual void wheelInstall(int)=0; virtual void smartInit()=0; virtual void systemTest()=0; };
这里没有把构造过程放进构造函数,是因为构造函数中无法动态绑定this,原因:子类构造函数会先调用父类的构造函数,而父类构造函数执行到动态绑定的语句时,与通过this的虚函数表(如果不知道要研究下了)查询相应的函数,而此时子类还未初始化完成,所以会抛出错误。
init()为对象构建过程,在这里该过程具有稳定性。
class Ferrari :public Car { string _name = "Ferrari"; virtual void designPrototype(); virtual void wheelInstall(int); virtual void smartInit(); virtual void systemTest(); public: void sayName() { cout << _name << endl; } Ferrari(){ Car::Init(); } }; void Ferrari::designPrototype() { this->_name = "Ferrari"; cout << "设计汽车原型中。。。" << endl; //实际实现代码。。。 cout << "原型设计完毕,准备进入下一阶段" << endl; } void Ferrari::wheelInstall(int time) { cout << "初始化第" << time << "个轮子" << endl; cout << "组装中" << endl; //实现代码,比如轮子类 cout << "轮子组装完毕,进入下一阶段" << endl; } void Ferrari::smartInit() { cout << "机动层初始化" << endl; cout << "机动层正常,进入下一阶段" << endl; } void Ferrari::systemTest() { cout << "汽车性能测试" << endl; cout << "安全测试" << endl; cout << "试跑正常" << endl; cout << "构建成功" << endl; }
测试:
好像,这样子已经可以很大程度上满足我们的需求了,而且结果似乎很完美。
builder模式的结构是怎么样的呢。
结构图:
其实就是把我们上面的一个大类,分成了director,builder,和product(它本身),director复制init工作,builder复制每一个小步骤,于是director是一个稳定的类,car的构建过程是相对稳定的,而builder是变化莫测的,因为它的每一步都可能是变化的,至少我们上面的代码,就是是轮子组装这一块,如果我们还有一个轮子类,那么我还是想象,法拉利和宝马的轮子应该是不一样的,轮子构造过程应该也可以是变化的,当然这种假设是抽象的,只是为了迎合这样一个模式,完全不用太较真。
所以用builder模式应该是:
产品职责变少:
class Car { string _name; public: virtual ~Car(){} virtual void sayName(){ cout << _name << endl; } string getName(){ return _name; } void setName(string name){ _name = name; } };
class Ferrari :public Car { public: void sayName() { cout << "i m a car,my name is:" << getName() << endl; } };
builder:
class CarBulider { protected: Car * _car; virtual void designPrototype() = 0; virtual void wheelInstall(int) = 0; virtual void smartInit() = 0; virtual void systemTest() = 0; virtual Car* getResult(){ return _car; }; friend class Director; public: virtual ~CarBulider(){} };
concrete builder:
class FerrariBulider :public CarBulider { virtual void designPrototype(); virtual void wheelInstall(int); virtual void smartInit(); virtual void systemTest(); public: FerrariBulider(){ } }; void FerrariBulider::designPrototype() { cout << "设计汽车原型中。。。" << endl; //实际实现代码。。。 CarBulider::_car = new Ferrari(); //这里创建对象,它将由客户去释放 CarBulider::_car->setName("Ferrari"); cout << "原型设计完毕,准备进入下一阶段" << endl; } void FerrariBulider::wheelInstall(int time) { cout << "初始化第" << time << "个轮子" << endl; cout << "组装中" << endl; //实现代码,比如轮子类 cout << "轮子组装完毕,进入下一阶段" << endl; } void FerrariBulider::smartInit() { cout << "机动层初始化" << endl; cout << "机动层正常,进入下一阶段" << endl; } void FerrariBulider::systemTest() { cout << "汽车性能测试" << endl; cout << "安全测试" << endl; cout << "试跑正常" << endl; cout << "构建成功" << endl; }
Diretor:
class Director { public: Director(){ } Car* construct(CarBulider &); }; Car* Director::construct(CarBulider &b) { //指针内存泄露问题,如果是这样调用construct(new carbulider). b.designPrototype(); for (int i = 0; i < 4; i++) { b.wheelInstall(i); } b.smartInit(); b.systemTest(); return b.getResult(); }
使用方式:
int main() { FerrariBulider b; Director d; Car *f = d.construct(b); f->sayName(); return 0; }
结果:
细节问题好头疼,c++实现方式很多,又要担心内存泄露。所以把builder之间改成引用,由用户觉决定。但是这个时候又设计到const的问题,如果用const那么相应的函数声明也应该改。