【设计模式】创建型模式之生成器Builder
2016-05-24 09:47
656 查看
生成器Builder是一种创建型设计模式,意在将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
下面是Builder模式的类图——
Builder:为创建一个Product对象的各个部件指定抽象接口。
ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,提供一个检索产品的接口。
Director:构造一个使用Builder接口的对象。
Product:表示被构造的复杂对象,ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时,或者当构造过程必须允许被构造的对象有不同的表示时,我们就可以尝试使用Builder模式了。从上面的类图中可以看出,客户创建Director对象,并用它所想要的Builder对象进行配置,一旦产品部件被生成,Director就会通知Builder,Builder处理Director的请求,并将部件添加到该产品中,客户从Builder中检索产品。Builder模式的好处就是只是提供给Director一个构造产品的抽象接口,却隐藏了这个产品的表示和内部结构,同时也隐藏了该产品是如何装配的,因此可以让我们改变一个产品的内部表示,将构造代码和表示代码分开,对构造过程进行更精细的控制。
下面是一个使用了Builder模式的例子。
测试代码如下:
例子中,CarBuilder类对应于类图中的Builder,定义了构造Car的几个接口,分别是汽车本身以及汽车的的发动机、地盘、车身、电气设备,还提供了一个获取最终Car的接口,这些函数都是virtual函数,这是必须的,当然也可以根据需要声明为纯虚函数。NormalCarBuilder类对应于类图中的ConcreteBuilder,具体实现了构造Car的接口,还保存了Car作为成员变量。ClientCar类对应于类图中的Director,其成员函数createCar对应于Director::construct,参数为指向Builder的指针,用于构造Car及其所有零部件,最后通过getCar获取构造完成的Car。Car是我们最终的产品,它包括了四个部分:发动机、地盘、车身、电气设备。当我们开始创建Car的时候,只需实例化NormalCarBuilder,把这个实例化对象作为参数传给ClientCar::createCar即可。可见,当一个产品有不同的零部件时,想要分离或隐藏产品的表示及装配时,使用Builder模式恰到好处。
下面是Builder模式的类图——
Builder:为创建一个Product对象的各个部件指定抽象接口。
ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,提供一个检索产品的接口。
Director:构造一个使用Builder接口的对象。
Product:表示被构造的复杂对象,ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时,或者当构造过程必须允许被构造的对象有不同的表示时,我们就可以尝试使用Builder模式了。从上面的类图中可以看出,客户创建Director对象,并用它所想要的Builder对象进行配置,一旦产品部件被生成,Director就会通知Builder,Builder处理Director的请求,并将部件添加到该产品中,客户从Builder中检索产品。Builder模式的好处就是只是提供给Director一个构造产品的抽象接口,却隐藏了这个产品的表示和内部结构,同时也隐藏了该产品是如何装配的,因此可以让我们改变一个产品的内部表示,将构造代码和表示代码分开,对构造过程进行更精细的控制。
下面是一个使用了Builder模式的例子。
class Engine; class Classis; class Body; class ElectricalEquipment; class Car { public: Car() : m_pEngine(0), m_pClassis(0), m_pBody(0), m_pEquipment(0) {} void addEngine(Engine *engine) { m_pEngine = engine; } void addClassis(Classis *classis) { m_pClassis = classis; } void addBody(Body *body) { m_pBody = body; } void addElectricalEquipment(ElectricalEquipment *equipment) { m_pEquipment = equipment; } private: Engine *m_pEngine; Classis *m_pClassis; Body *m_pBody; ElectricalEquipment *m_pEquipment; }; class Engine {}; class Classis {}; class Body {}; class ElectricalEquipment {}; class CarBuilder { public: virtual void buildCar() {} virtual void buildEngine() {} virtual void buildClassis() {} virtual void buildBody() {} virtual void buildElectricalEquipment() {} virtual Car* getCar() { return 0; } protected: CarBuilder() {} }; class NormalCarBuilder : public CarBuilder { public: NormalCarBuilder() : m_pCar(0) {} void buildCar() { m_pCar = new Car; } void buildEngine() { m_pCar ? m_pCar->addEngine(new Engine) : (void)0; } void buildClassis() { m_pCar ? m_pCar->addClassis(new Classis) : (void)0; } void buildBody() { m_pCar ? m_pCar->addBody(new Body) : (void)0; } void buildElectricalEquipment() { m_pCar ? m_pCar->addElectricalEquipment(new ElectricalEquipment) : (void)0; } Car* getCar() { return m_pCar; } private: Car* m_pCar; }; class CarClient { public: Car* createCar(CarBuilder *builder) { if (builder) { builder->buildCar(); builder->buildEngine(); builder->buildClassis(); builder->buildBody(); builder->buildElectricalEquipment(); return builder->getCar(); } return 0; } };
测试代码如下:
CarClient cc; NormalCarBuilder ncb; cc.createCar(&nbcb);
例子中,CarBuilder类对应于类图中的Builder,定义了构造Car的几个接口,分别是汽车本身以及汽车的的发动机、地盘、车身、电气设备,还提供了一个获取最终Car的接口,这些函数都是virtual函数,这是必须的,当然也可以根据需要声明为纯虚函数。NormalCarBuilder类对应于类图中的ConcreteBuilder,具体实现了构造Car的接口,还保存了Car作为成员变量。ClientCar类对应于类图中的Director,其成员函数createCar对应于Director::construct,参数为指向Builder的指针,用于构造Car及其所有零部件,最后通过getCar获取构造完成的Car。Car是我们最终的产品,它包括了四个部分:发动机、地盘、车身、电气设备。当我们开始创建Car的时候,只需实例化NormalCarBuilder,把这个实例化对象作为参数传给ClientCar::createCar即可。可见,当一个产品有不同的零部件时,想要分离或隐藏产品的表示及装配时,使用Builder模式恰到好处。
相关文章推荐
- Android进阶UI之使用自定义字体
- java入门教程-2.7 Java StringBuffer与StringBuider
- Vue.js的表格分页组件
- ReflectionToStringBuilder类
- MiniUI总结
- [iOS]关于状态栏(UIStatusBar)的若干问题
- Android As报错:Warning:Gradle version 2.10 is required. Current version is 2.8. If using th....
- UIPickerView的使用
- 表格UITableViewCell定制和使用
- Java基础——StringBuffer,StringBuilder使用,超市管理系统
- Android高级UI ACharEngine实现图形绘制
- Android高级UI PullToRefresh下拉刷新
- hdu 2604Queuing dp+ 矩阵快速幂
- IOS中UITableViewCell使用详解
- A slave with the same server_uuid as this slave has connected to the master
- “哎哟!蛮吊的” 之 Handler,Looper,messagequeue,AsyncTask图形总结
- 编译QT时出现lib/libQtGui.so: undefined reference to `ts_read_raw'的解决办法
- Codeforces Round #353 (Div. 2) A. Infinite Sequence
- IOS 画图板-使用UIBezierPath
- LeetCode 115. Distinct Subsequences(子序列数量)