Builder模式
目录 |
1 问题
生活中有着很多的Builder的例子,个人觉得大学生活就是一个Builder模式的最好体验:要完成大学教育,一般将大学教育过程分成4个学期进行,因此学习可以看作是构建完整大学教育的一个部分构建过程,每个人经过这4年的(4个阶段)构建过程得到的最后的结果不一样,因为可能在四个阶段的构建中引入了很多的参数(每个人的机会和际遇不完全相同)。
Builder模式要解决的也正是这样的问题:当我们要创建的对象很复杂的时候(通常是由很多其他的对象组合而成),我们要将复杂对象的创建过程和这个对象的表示(展示)分离开来,这样做的好处就是通过一步步的进行复杂对象的构建,由于在每一步的构造过程中可以引入参数,使得经过相同的步骤创建最后得到的对象的展示不一样。
2 模式选择
Builder模式的典型结构图为:
图1:Builder Pattern结构图
Builder:为创建一个Product对象的各个部件制定抽象接口。
ConcreteBuilder:具体的建造者,它负责真正的生产。
Director:导演, 建造的执行者,它负责发布命令。
Product:最终消费的产品。
各类之间的交互关系如下图所示:

Builder模式的关键是其中的Director对象并不直接返回对象,而是通过一步步(BuildPartA,BuildPartB,BuildPartC)来一步步进行对象的创建。当然这里Director可以提供一个默认的返回对象的接口(即返回通用的复杂对象的创建,即不指定或者特定唯一指定BuildPart中的参数)。
下面我们举个例子来加深我们对Builder模式的理解。 比如我们要通过一个汽车加工厂,生产一辆汽车;汽车由车轮 方向盘 发动机还有各种小零件等等组成,它的基本组装步骤是:
- 生产车轮
- 生产方向盘
- 生产发动机
- .................
通过上面的分析,我们知道,该范例满足Builder模式的应用场景所提到的条件:
- 对象的创建:我们需要创建汽车对象
- 创建的是一个复合对象:我们需要创建的汽车对象是具有车轮 方向盘 发动等复合属性的复合对象
下面我们用Builder设计模式来抽象以上组装过程:
- Client:买汽车的顾客。通过向Director申请,然后Director让Builder组装汽车
- Director:负责生产汽车的经理,或者销售人员
- Builder:汽车组装抽象类
- ConcreteBuilder:生产汽车的直接员工
3 示例代码
namespace DesignPattern_Builder { class Product1 { /*...*/ } ; class Product2 { /*...*/ } ; // class Builder class Builder //抽象基类 { public: virtual void BuilderPartA() {} //提供缺省实现 virtual void BuilderPartB() {} virtual void BuilderPartC() {} protected: Builder() {} } ; // class ConcreteBuilder1 class ConcreteBuilder1 : public Builder //创建Product1 { public: ConcreteBuilder1() : _product(NULL) {} virtual void BuilderPartA() { /*...*/ } virtual void BuilderPartB() { /*...*/ } virtual void BuilderPartC() { /*...*/ } virtual Product1* GetProduct1() { return _product ; } //返回创建的Product1对象 private: Product1 *_product ; } ; // class ConcreteBuilder2 class ConcreteBuilder2 : public Builder //创建Product2 { public: ConcreteBuilder2() : _product(NULL) {} virtual void BuilderPartA() { /*...*/ } virtual void BuilderPartB() { /*...*/ } virtual void BuilderPartC() { /*...*/ } virtual Product2* GetProduct2() { return _product ; } //返回创建的Product2对象 private: Product2 *_product ; } ; // class Director class Director { public: //创建对象(Director并不知道具体创建出来的对象是什么样的,只有调用该函数的client知道) void Construct(Builder *builder) { builder->BuilderPartA() ; builder->BuilderPartB() ; builder->BuilderPartC() ; } } ; }
客户端代码:
{ using namespace DesignPattern_Builder ; Director director ; // 创建第一种对象 ConcreteBuilder1 *pBuilder1 = new ConcreteBuilder1() ; director.Construct(pBuilder1) ; Product1 *product1 = pBuilder1->GetProduct1() ; // 创建第二种对象 ConcreteBuilder2 *pBuilder2 = new ConcreteBuilder2() ; director.Construct(pBuilder2) ; Product2 *product2 = pBuilder2->GetProduct2() ; }
4 实例
例子一。如下图所示:

上图的功能是是把一个RTF文件转换为多种正文格式。RTFReader进行语法分析,然后将所有的token串逐一转换。可见builder就是一步步地把各个部分组装为一个整体。它封闭了组装的方法,组装出来的对象也大相径庭。
5 讨论
GoF在《设计模式》一书中给出的关于Builder模式的意图是非常容易理解、间接的:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示(在示例代码中可以通过传入不同的参数实现这一点)。
Builder模式和AbstractFactory模式在功能上很相似,因为都是用来创建大的复杂的对象,它们的区别是:Builder模式强调的是一步步创建对象,并通过相同的创建过程可以获得不同的结果对象,一般来说Builder模式中对象不是直接返回的。而在AbstractFactory模式中对象是直接返回的,AbstractFactory模式强调的是为创建多个相互依赖的对象提供一个同一的接口。
6 参见
- c++设计模式(3)-Builder(ZT). Henry. 2008-08-29 22:54.
- 设计模式解析之——BUILDER模式(K_ECKEL转自微软高校博客K_ECKEL'S MINDVIEW). K_Eckel. 2005-04-05.
- Builder模式. ldjsyl. 2008-05-06.