建造者模式(创建型)
建造者模式
建造者模式又称为生成器模式,是一种对象创建型模式,它将客户端与包含多个组成部分或部件的复杂对象的创建过程解耦,客户端无需知道复杂对象的内部组成部分与装配方式,只需要知道所需建造者的类型即可。具体的建造者关注如何一步一步创建一个复杂对象,不同的具体创建者定义不同的创建过程,且它们之间相互独立,增加新的建造者非常方便,无需修改已有代码,系统扩展性好。
意图
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
参与者
Builder
为创建一个Product对象的各个部件指定抽象接口Concrete Builer
实现Builder的接口以构造和装配该产品的各个部件;
定义并明确它所创建的表示;
提供一个检索产品的接口Director
构造一个使用Builder接口的对象Product
表示被构造的复杂对象,Concrete Builder 创建该产品的内部表示并定义它的装配过程;
包含定义组成部件的类,包括将这些部件装配成最终产品的接口
模式结构
基本的模式结构图
各个参与者的协作图
代码实现
首先定义抽象产品类,包括
AddPart()
和ShowProduct()
分别定义组成Product的各个部分
及显示产品:1
2
3
4
5
6class AbstractProduct
{
public:
virtual void AddPart(const char* part) = 0; //产品的部件操作接口
virtual void ShowProduct() = 0; // 打印显示产品
};再定义两个具体的产品ProductA、ProductB,并实现各自的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40// Product A
class ProductA: public AbstractProduct
{
private:
vector<const char*> m_VecPart;
public:
void AddPart(const char *part)
{
m_VecPart.push_back(part);
}
void ShowProduct()
{
cout << "I am Product A!" << endl;
for (vector<const char*>::iterator it = m_VecPart.begin(); it != m_VecPart.end(); ++it)
{
cout << *it << endl;
}
}
};
// Product B
class ProductB: public AbstractProduct
{
private:
vector<const char*> m_VecPart;
public:
void AddPart(const char *part)
{
m_VecPart.push_back(part);
}
void ShowProduct()
{
cout << "I am Product B!" << endl;
for (vector<const char*>::iterator it = m_VecPart.begin(); it != m_VecPart.end(); ++it)
{
cout << *it << endl;
}
}
};定义抽象的Builder类:
1
2
3
4
5
6
7class AbstractBuilder
{
public:
virtual void BuilderPart1() = 0; // 构建产品部件1
virtual void BuilderPart2() = 0; // 构建产品部件2
virtual AbstractProduct* GetProduct() = 0; // 获取构建的产品
};定义具体两个Builder,BuilderA及BuilderB 分别构建和组装产品A和B:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47// Builder A
class BuilderA: public AbstractBuilder //构建产品A内部部分
{
private:
AbstractProduct *m_pProduct; // 被构建的抽象产品指针
public:
BuilderA()
{
m_pProduct = new ProductA(); //构建产品A
}
void BuilderPart1()
{
m_pProduct->AddPart("A Part 1 is Completed!");
}
void BuilderPart2()
{
m_pProduct->AddPart("A Part 2 is Completed!");
}
AbstractProduct* GetProduct() // 返回构建的产品A
{
return m_pProduct;
}
};
// Builder B
class BuilderB: public AbstractBuilder //构建产品B内部部分
{
private:
AbstractProduct *m_pProduct; // 被构建的抽象产品指针
public:
BuilderB()
{
m_pProduct = new ProductB(); //构建产品B
}
void BuilderPart1()
{
m_pProduct->AddPart("B Part 1 is Completed!");
}
void BuilderPart2()
{
m_pProduct->AddPart("B Part 2 is Completed!");
}
AbstractProduct* GetProduct() // 返回构建的产品B
{
return m_pProduct;
}
};定义引导者Director类,提供一个创建最终产品的接口,该接口使用Builder的方法来组装创建产品:
1
2
3
4
5
6
7
8
9
10
11
12class Director
{
private:
AbstractBuilder *m_pBuilder;
public:
Director(AbstractBuilder *pbuilder): m_pBuilder(pbuilder) {};
void CreateProduct() // 组装整个产品
{
m_pBuilder->BuilderPart1();
m_pBuilder->BuilderPart2();
}
};测试建造者模式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22void BuilderTest()
{
AbstractBuilder *pAB = new BuilderA(); // 构建产品A
Director *pD = new Director(pAB);
pD->CreateProduct(); // 引导者负责通过 Builder 组装产品
AbstractProduct *pAP = pAB->GetProduct(); // 建造者负责 具体的Builder 组装产品,并提供获取产品接口
pAP->ShowProduct();
AbstractBuilder *pAB2 = new BuilderB(); // 构建产品B
Director *pD2 = new Director(pAB2);
pD2->CreateProduct(); // 引导者负责通过 Builder 组装产品
AbstractProduct *pAP2 = pAB2->GetProduct(); // 建造者负责 具体的Builder 组装产品,并提供获取产品接口
pAP2->ShowProduct();
delete pAB; pAB = NULL;
delete pD; pD = NULL;
delete pAP; pAP = NULL;
delete pAB2; pAB2 = NULL;
delete pD2; pD2 = NULL;
delete pAP2; pAP2 = NULL;
}
运行结果:
I am Product A!
A Part 1 is Completed!
A Part 2 is Completed!
I am Product B!
B Part 1 is Completed!
B Part 2 is Completed!
使用场景
- 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性
- 需要生成的产品对象的属性相互依赖,需要指定其生成顺序
- 对象的创建过程独立于创建该对象的类,在Builder模式中通过引入Director类,将创建的过程封装在Director类中而非Builder或Client类中
- 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品
优缺点
- 优点:
- 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象
- 当需要创建复杂对象的过程中,复杂对象没有多少共同的特点,很难抽象出来时,
而复杂对象的组装又有一定的相似点时,建造者模式就可以发挥出作用 - 由于指挥者类针对抽象建造者编程,增加新的具体建造者无须修改原有类库的代码,系统扩展方便,符合“开闭原则”
- 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程
- 缺点:
- 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,例如很多组成部分都不相同,不适合使用建造者模式,因此其使用范围受到一定的限制
- 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加系统的理解难度和运行成本
与工厂模式的区别
都属于创建型的设计模式,所以二者之间是有公共点,但是建造者模式注重于对象组合,即不同的小对象组成一个整体的复杂大对象;而抽象工厂模式针对于接口编程,只是对外提供创建对象的工厂接口,不负责对象之后的处理
建造者模式具体实例
构建一个人对象,包括胖和瘦两种类型,每个人都包含头、身体、手和脚四部分
代码实现
抽象的ManBuilder类:
1
2
3
4
5
6
7
8
9
10// 抽象的人建造者类
class ManBuilder
{
public:
// 建造人的不同部位
virtual void BuilderHead() = 0;
virtual void BuilderBody() = 0;
virtual void BuilderHand() = 0;
virtual void BuilderLeg() = 0;
};具体的两个建造者ThinBuilder和FatBuilder分别构建胖子和瘦子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43// 具体的瘦人建造者
class ThinBuilder: public ManBuilder
{
public:
void BuilderHead()
{
cout << "Thin Builder Head" << endl;
}
void BuilderBody()
{
cout << "Thin Builder Body" << endl;
}
void BuilderHand()
{
cout << "Thin Builder Hand" << endl;
}
void BuilderLeg()
{
cout << "Thin Builder Leg" << endl;
}
};
// 具体的胖人建造者
class FatBuilder: public ManBuilder
{
public:
void BuilderHead()
{
cout << "Fat Builder Head" << endl;
}
void BuilderBody()
{
cout << "Fat Builder Body" << endl;
}
void BuilderHand()
{
cout << "Fat Builder Hand" << endl;
}
void BuilderLeg()
{
cout << "Fat Builder Leg" << endl;
}
};最终创建人对象的ManDirector引导者类调用ManDirector的方法来组装和创建具体类型的人:
1
2
3
4
5
6
7
8
9
10
11
12
13
14class ManDirector
{
private:
ManBuilder *m_pBuilder; // 抽象的ManBuilder
public:
ManDirector(ManBuilder *pBuilder): m_pBuilder(pBuilder) {};
void CreateMan() // 使用ManBuilder的方法构建最终的Man
{
m_pBuilder->BuilderHead();
m_pBuilder->BuilderBody();
m_pBuilder->BuilderHand();
m_pBuilder->BuilderLeg();
}
};客户端测试:
1
2
3
4
5
6
7
8
9
10
11
12
13void ManBuilderTest()
{
ManBuilder *pMB = new ThinBuilder();
ManDirector MD(pMB);
MD.CreateMan();
ManBuilder *pMB2 = new FatBuilder();
ManDirector MD2(pMB2);
MD2.CreateMan();
delete pMB; pMB = NULL;
delete pMB2; pMB2 = NULL;
}
运行结果:
Thin Builder Head
Thin Builder Body
Thin Builder Hand
Thin Builder Leg
Fat Builder Head
Fat Builder Body
Fat Builder Hand
Fat Builder Leg