Builder模式仍然属于创建型模式,主要体现了OO中“封装”和“多态”两个特性。
还是引一个简单的例子来说明Builder模式的意义。
假设我们设计的游戏中需要创建一个比较复杂的房屋对象,房屋对象有很多部分组成,比如说有门,窗户,墙,地板等等。当我们在将这个房屋实现之后,可能随着需求的改变需要对门进行更换,将原来的木门换成铁门。这时候的问题就是:如何改变组成部分而对房屋整体不做改变?
到了这里就需要我们对房屋进行抽象:房屋拥有门,窗户,墙等部分,这些部分可能容易发生变化。房屋也有其稳定的结构,这结构就是如何将门,窗户,墙等部分如何连接起来的算法。

上图中引入了Builder这一概念,我们可以把他理解成为生产各个部件(如门,窗户)的一个生成器(有点像之前说的工厂,但又不完全是),代码中具体将其实现成为抽象类。红线以上是相对稳定的部分,红线以下是相对易变的部分。其中构建算法(即如何连接房屋中各个部件间的关系)稳定,但部件类型依赖于Builder,Builder具体实现为何种方案(木门还是铁门?)这全由多态的动态绑定机制决定(即交由客户代码来决定)。
动机:
软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临剧烈变化,但将其组合在一起的算法却相对稳定。
意图:
将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。(GoF)
GoF给出的这个意图相当的晦涩难懂,关键就在“同样的构建过程”和“不同的表示”。“同样的构建过程”就是指前面分析中的稳定构建算法;“不同的表示”就是不同部件组合出来的不同的对象。
设计思路:
先看UML图

图中Director使用Builder的对象,他的Construct方法就是“意图”中所指的“同样的构建过程”,即对象的稳定构建算法。Builder作为参数传入Construct以提供具体的对象对象。
而Builder类作为接口实现,提供Product中各个部件的生成接口;ConcreteBuilder来对接口具体实现,并有一个返回具体Product的方法GetResult。

上图描述了客户程序,Director类,ConcreteBuilder类如何进行协作。首先客户代码确定需要何种类型的对象,创建相应的ConcreteBuilder;再创建Director类,将ConcreteBuilder作为参数传入;在Construct方法中创建对象中A,B,C三个子部分,并对这些子部分进行合理的组织;最后通过ConcreteBuilder的GetResult方法获得所需对象。
Builder模式和Abstract Factory模式很容易让人混淆,因为他们都可以产生不同系列的对象。
但是两者还是有本质差别的:
1.两者目的不同。Builder模式是为了产生单个复杂对象;Abstract Factory模式是为了产生一系列不同风格的对象。(Builder模式也产生一系列对象,但他们都是复杂对象的子部分)
2.Builder模式在最后一步返回对象;Abstract Factory模式中的系列对象是立即返回的。
自己实现的示例代码,仅供参考:
Main.cpp
1
/**/////////////////////////////////////////////////////////////////////////// 2
// BuilderTest for Builder Pattern Test
3
//
4
/**/////////////////////////////////////////////////////////////////////////// 5
6
#include "stdafx.h"
7
#include "AbstractInfo.h"
8
#include "Builder.h"
9
#include "ModernHouse.h"
10
#include "Castle.h"
11
#include <iostream>
12
using namespace std;
13
14
//对应UML图中的Director类
15
class HouseManager
16

{
17
public:
18
//对House中的子部件进行组装,该部分被认为相对稳定
19
void construct(Builder* builder)
20
{
21
builder->buildDoor();
22
builder->buildWindow();
23
builder->buildWall();
24
builder->buildFloor();
25
builder->buildCeiling();
26
}
27
};
28
29
int _tmain(int argc, _TCHAR* argv[])
30

{
31
//创建ConcreteBuilder
32
Builder* builder = new CastleBuilder();
33
//HouseManager对应Director,construct方法对House的子部件(门,窗户等)进行组装
34
HouseManager* houseManager = new HouseManager();
35
houseManager->construct(builder);
36
//得到需要的结果(Castle)
37
House* house = builder->getResult();
38
39
delete house;
40
delete houseManager;
41
delete builder;
42
return 0;
43
}
各种抽象类,包括房屋,门,窗户。。。
AbstracInfo.h
1
#pragma once
2
3
class Door
4

{
5
protected:
6
Door()
{}
7
};
8
9
class Window
10

{
11
protected:
12
Window()
{}
13
};
14
15
class Wall
16

{
17
protected:
18
Wall()
{}
19
};
20
21
class Floor
22

{
23
protected:
24
Floor()
{}
25
};
26
27
class Ceiling
28

{
29
protected:
30
Ceiling()
{}
31
};
32
33
class House
34

{
35
protected:
36
House(Door* d,Window* wd,Wall* wl,Floor* f,Ceiling* c)
{}
37
};
38
39
Builder.h
1
#pragma once
2
#include "AbstractInfo.h"
3
4
class Builder
5

{
6
public:
7
virtual void buildDoor() = 0;
8
virtual void buildWindow() = 0;
9
virtual void buildWall() = 0;
10
virtual void buildFloor() = 0;
11
virtual void buildCeiling() = 0;
12
virtual House* getResult() = 0;
13
};
14
15
Castle.h
1
#pragma once
2
#include "AbstractInfo.h"
3
#include "Builder.h"
4
#include <iostream>
5
using namespace std;
6
7
class Castle : public House
8

{
9
public:
10
Castle(Door* d,Window* wd,Wall* wl,Floor* f,Ceiling* c)
11
:House(d,wd,wl,f,c)
12
{
13
cout<<"Create a Castle with Door, Window, Wall, Floor, Ceiling"<<endl;
14
}
15
};
16
17
class CastleDoor : public Door
18

{
19
public:
20
CastleDoor()
21
{
22
cout<<"the Castle Door is created"<<endl;
23
}
24
};
25
26
class CastleWindow : public Window
27

{
28
public:
29
CastleWindow()
30
{
31
cout<<"the Castle Window is created"<<endl;
32
}
33
};
34
35
class CastleWall : public Wall
36

{
37
public:
38
CastleWall()
39
{
40
cout<<"the Castle Wall is created"<<endl;
41
}
42
};
43
44
class CastleFloor : public Floor
45

{
46
public:
47
CastleFloor()
48
{
49
cout<<"the Castle Floor is created"<<endl;
50
}
51
};
52
53
class CastleCeiling : public Ceiling
54

{
55
public:
56
CastleCeiling()
57
{
58
cout<<"the Castle Ceiling is created"<<endl;
59
}
60
};
61
62
class CastleBuilder : public Builder
63

{
64
private:
65
Door* door;
66
Window* window;
67
Wall* wall;
68
Floor* floor;
69
Ceiling* ceiling;
70
public:
71
void buildDoor()
72
{
73
door = new CastleDoor();
74
}
75
void buildWindow()
76
{
77
window = new CastleWindow();
78
}
79
void buildWall()
80
{
81
wall = new CastleWall();
82
}
83
void buildFloor()
84
{
85
floor = new CastleFloor();
86
}
87
void buildCeiling()
88
{
89
ceiling = new CastleCeiling();
90
}
91
Castle* getResult()
92
{
93
return new Castle(door,window,wall,floor,ceiling);
94
}
95
~CastleBuilder()
96
{
97
if (door != NULL)
{ delete door;}
98
if (window != NULL)
{ delete window;}
99
if (wall != NULL)
{ delete wall;}
100
if (floor != NULL)
{ delete floor;}
101
if (ceiling != NULL)
{ delete ceiling;}
102
}
103
};
104