`
tudusi
  • 浏览: 1085444 次
文章分类
社区版块
存档分类
最新评论

建造者模式(Builder Pattern)

 
阅读更多



概述

在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法确相对稳定。如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?这就是要说的建造者模式。

本文通过现实生活中的买KFC的例子,用图解的方式来诠释建造者模式。

意图

将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

模型图

生活中的例子

生成器模式将复杂对象的构建与对象的表现分离开来,这样使得同样的构建过程可以创建出不同的表现。这种模式用于快餐店制作儿童餐。典型的儿童餐包括一个主食,一个辅食,一杯饮料和一个玩具(例如汉堡、炸鸡、可乐和玩具车)。这些在不同的儿童餐中可以是不同的,但是组合成儿童餐的过程是相同的。无论顾客点的是汉堡,三名治还是鸡肉,过程都是一样的。柜台的员工直接把主食,辅食和玩具放在一起。这些是放在一个袋子中的。饮料被倒入杯中,放在袋子外边。这些过程在相互竞争的餐馆中是同样的。

实现过程图解

在这里我们还是以去KFC店买套餐为例子,示意图如下:

客户端:顾客。想去买一套套餐(这里面包括汉堡,可乐,薯条),可以有1号和2号两种套餐供顾客选择。

指导者角色:收银员。知道顾客想要买什么样的套餐,并告诉餐馆员工去准备套餐。

建造者角色:餐馆员工。按照收银员的要求去准备具体的套餐,分别放入汉堡,可乐,薯条等。

产品角色:最后的套餐,所有的东西放在同一个盘子里面。

下面开始我们的买套餐过程。

1.客户创建Derector对象,并用它所想要的Builder对象进行配置。顾客进入KFC店要买套餐,先找到一个收银员,相当于创建了一个指导者对象。这位收银员给出两种套餐供顾客选择:1普通套餐,2黄金套餐。完成的工作如时序图中红色部分所示。

程序实现:

1usingSystem;
2usingSystem.Configuration;
3usingSystem.Reflection;
4
5namespaceKFC
6{
7///<summary>
8///Client类
9///</summary>

10publicclassClient
11{
12publicstaticvoidMain(string[]args)
13{
14FoodManagerfoodmanager=newFoodManager();
15
16Builderinstance;
17
18Console.WriteLine("PleaseEnterFoodNo:");
19
20stringNo=Console.ReadLine();
21
22stringfoodType=ConfigurationSettings.AppSettings["No"+No];
23
24instance=(Builder)Assembly.Load("KFC").CreateInstance("KFC."+foodType);
25
26foodmanager.Construct(instance);
27}
28}
29}
30

产品(套餐)类:

1usingSystem;
2usingSystem.Collections;
3
4namespaceKFC
5{
6///<summary>
7///Food类,即产品类
8///</summary>

9publicclassFood
10{
11Hashtablefood=newHashtable();
12
13///<summary>
14///添加食品
15///</summary>
16///<paramname="strName">食品名称</param>
17///<paramname="Price">价格</param>

18publicvoidAdd(stringstrName,stringPrice)
19{
20food.Add(strName,Price);
21}
22
23///<summary>
24///显示食品清单
25///</summary>

26publicvoidShow()
27{
28IDictionaryEnumeratormyEnumerator=food.GetEnumerator();
29Console.WriteLine("FoodList:");
30Console.WriteLine("------------------------------");
31stringstrfoodlist="";
32while(myEnumerator.MoveNext())
33{
34strfoodlist=strfoodlist+"\n\n"+myEnumerator.Key.ToString();
35strfoodlist=strfoodlist+":\t"+myEnumerator.Value.ToString();
36}
37Console.WriteLine(strfoodlist);
38Console.WriteLine("\n------------------------------");
39}
40}
41}
42

2.指导者通知建造器。收银员(指导者)告知餐馆员工准备套餐。这里我们准备套餐的顺序是:放入汉堡,可乐倒入杯中,薯条放入盒中,并把这些东西都放在盘子上。这个过程对于普通套餐和黄金套餐来说都是一样的,不同的是它们的汉堡,可乐,薯条价格不同而已。如时序图红色部分所示:

程序实现:

1usingSystem;
2
3namespaceKFC
4{
5///<summary>
6///FoodManager类,即指导者
7///</summary>

8publicclassFoodManager
9{
10publicvoidConstruct(Builderbuilder)
11{
12builder.BuildHamb();
13
14builder.BuildCoke();
15
16builder.BuildChip();
17}
18}
19}
20

3.建造者处理指导者的要求,并将部件添加到产品中。餐馆员工(建造者)按照收银员要求的把对应的汉堡,可乐,薯条放入盘子中。这部分是建造者模式里面富于变化的部分,因为顾客选择的套餐不同,套餐的组装过程也不同,这步完成产品对象的创建工作。

程序实现:

1usingSystem;
2
3namespaceKFC
4{
5///<summary>
6///Builder类,即抽象建造者类,构造套餐
7///</summary>

8publicabstractclassBuilder
9{
10///<summary>
11///添加汉堡
12///</summary>

13publicabstractvoidBuildHamb();
14
15///<summary>
16///添加可乐
17///</summary>

18publicabstractvoidBuildCoke();
19
20///<summary>
21///添加薯条
22///</summary>

23publicabstractvoidBuildChip();
24
25///<summary>
26///返回结果
27///</summary>
28///<returns>食品对象</returns>

29publicabstractFoodGetFood();
30}
31}
32

1usingSystem;
2
3namespaceKFC
4{
5///<summary>
6///NormalBuilder类,具体构造者,普通套餐
7///</summary>

8publicclassNormalBuilder:Builder
9{
10privateFoodNormalFood=newFood();
11
12publicoverridevoidBuildHamb()
13{
14NormalFood.Add("NormalHamb","¥10.50");
15}
16
17publicoverridevoidBuildCoke()
18{
19NormalFood.Add("CokeCole","¥4.50");
20}
21
22publicoverridevoidBuildChip()
23{
24NormalFood.Add("FireChips","¥2.00");
25}
26
27publicoverrideFoodGetFood()
28{
29returnNormalFood;
30}
31
32}
33}
34

1usingSystem;
2
3namespaceKFC
4{
5///<summary>
6///GoldBuilder类,具体构造者,黄金套餐
7///</summary>

8publicclassGoldBuilder:Builder
9{
10privateFoodGoldFood=newFood();
11
12publicoverridevoidBuildHamb()
13{
14GoldFood.Add("GoldHamb","¥13.50");
15}
16
17publicoverridevoidBuildCoke()
18{
19GoldFood.Add("CokeCole","¥4.50");
20}
21
22publicoverridevoidBuildChip()
23{
24GoldFood.Add("FireChips","¥3.50");
25}
26
27publicoverrideFoodGetFood()
28{
29returnGoldFood;
30}
31
32}
33}
34

4.客户从建造者检索产品。从餐馆员工准备好套餐后,顾客再从餐馆员工那儿拿回套餐。这步客户程序要做的仅仅是取回已经生成的产品对象,如时序图中红色部分所示。

完整的客户程序:

1usingSystem;
2usingSystem.Configuration;
3usingSystem.Reflection;
4
5namespaceKFC
6{
7///<summary>
8///Client类
9///</summary>

10publicclassClient
11{
12publicstaticvoidMain(string[]args)
13{
14FoodManagerfoodmanager=newFoodManager();
15
16Builderinstance;
17
18Console.WriteLine("PleaseEnterFoodNo:");
19
20stringNo=Console.ReadLine();
21
22stringfoodType=ConfigurationSettings.AppSettings["No"+No];
23
24instance=(Builder)Assembly.Load("KFC").CreateInstance("KFC."+foodType);
25
26foodmanager.Construct(instance);
27
28Foodfood=instance.GetFood();
29food.Show();
30
31Console.ReadLine();
32}
33}
34}
35

通过分析不难看出,在这个例子中,在准备套餐的过程是稳定的,即按照一定的步骤去做,而套餐的组成部分则是变化的,有可能是普通套餐或黄金套餐等。这个变化就是建造者模式中的“变化点“,就是我们要封装的部分。

另外一个例子

在这里我们再给出另外一个关于建造房子的例子。客户程序通过调用指导者(CDirector class)的BuildHouse()方法来创建一个房子。该方法有一个布尔型的参数blnBackyard,当blnBackyard为假时指导者将创建一个Apartment(Concrete Builder),当它为真时将创建一个Single Family Home(Concrete Builder)。这两种房子都实现了接口Ihouse。

程序实现:

1//关于建造房屋的例子
2usingSystem;
3usingSystem.Collections;
4
5///<summary>
6///抽象建造者
7///</summary>

8publicinterfaceIHouse
9{
10boolGetBackyard();
11longNoOfRooms();
12stringDescription();
13}
14
15///<summary>
16///具体建造者
17///</summary>

18publicclassCApt:IHouse
19{
20privateboolmblnBackyard;
21privateHashtableRooms;
22publicCApt()
23{
24CRoomroom;
25Rooms=newHashtable();
26room=newCRoom();
27room.RoomName="MasterBedroom";
28Rooms.Add("room1",room);
29
30room=newCRoom();
31room.RoomName="SecondBedroom";
32Rooms.Add("room2",room);
33
34room=newCRoom();
35room.RoomName="LivingRoom";
36Rooms.Add("room3",room);
37
38mblnBackyard=false;
39}
40
41publicboolGetBackyard()
42{
43returnmblnBackyard;
44}
45publiclongNoOfRooms()
46{
47returnRooms.Count;
48}
49publicstringDescription()
50{
51IDictionaryEnumeratormyEnumerator=Rooms.GetEnumerator();
52stringstrDescription;
53strDescription="ThisisanApartmentwith"+Rooms.Count+"Rooms\n";
54strDescription=strDescription+"ThisApartmentdoesn'thaveabackyard\n";
55while(myEnumerator.MoveNext())
56{
57strDescription=strDescription+"\n"+myEnumerator.Key+"\t"+((CRoom)myEnumerator.Value).RoomName;
58}
59returnstrDescription;
60}
61}
62
63///<summary>
64///具体建造者
65///</summary>

66publicclassCSFH:IHouse
67{
68privateboolmblnBackyard;
69privateHashtableRooms;
70publicCSFH()
71{
72CRoomroom;
73Rooms=newHashtable();
74
75room=newCRoom();
76room.RoomName="MasterBedroom";
77Rooms.Add("room1",room);
78
79room=newCRoom();
80room.RoomName="SecondBedroom";
81Rooms.Add("room2",room);
82
83room=newCRoom();
84room.RoomName="ThirdRoom";
85Rooms.Add("room3",room);
86
87room=newCRoom();
88room.RoomName="LivingRoom";
89Rooms.Add("room4",room);
90
91room=newCRoom();
92room.RoomName="GuestRoom";
93Rooms.Add("room5",room);
94
95mblnBackyard=true;
96
97}
98
99publicboolGetBackyard()
100{
101returnmblnBackyard;
102}
103publiclongNoOfRooms()
104{
105returnRooms.Count;
106}
107publicstringDescription()
108{
109IDictionaryEnumeratormyEnumerator=Rooms.GetEnumerator();
110stringstrDescription;
111strDescription="ThisisanSingleFamilyHomewith"+Rooms.Count+"Rooms\n";
112strDescription=strDescription+"Thishousehasabackyard\n";
113while(myEnumerator.MoveNext())
114{
115strDescription=strDescription+"\n"+myEnumerator.Key+"\t"+((CRoom)myEnumerator.Value).RoomName;
116}
117returnstrDescription;
118}
119}
120
121publicinterfaceIRoom
122{
123stringRoomName{get;set;}
124}
125
126publicclassCRoom:IRoom
127{
128privatestringmstrRoomName;
129publicstringRoomName
130{
131get
132{
133returnmstrRoomName;
134}
135set
136{
137mstrRoomName=value;
138}
139}
140}
141
142///<summary>
143///指导者
144///</summary>

145publicclassCDirector
146{
147publicIHouseBuildHouse(boolblnBackyard)
148{
149if(blnBackyard)
150{
151returnnewCSFH();
152}
153else
154{
155returnnewCApt();
156}
157}
158}
159
160///<summary>
161///客户程序
162///</summary>

163publicclassClient
164{
165staticvoidMain(string[]args)
166{
167CDirectorobjDirector=newCDirector();
168IHouseobjHouse;
169
170stringInput=Console.ReadLine();
171objHouse=objDirector.BuildHouse(bool.Parse(Input));
172
173Console.WriteLine(objHouse.Description());
174Console.ReadLine();
175}
176}
177
178

建造者模式的几种演化

省略抽象建造者角色

系统中只需要一个具体建造者,省略掉抽象建造者,结构图如下:

指导者代码如下:

1classDirector
2{
3privateConcreteBuilderbuilder;
4
5publicvoidConstruct()
6{
7builder.BuildPartA();
8builder.BuildPartB();
9}
10}

省略指导者角色

抽象建造者角色已经被省略掉,还可以省略掉指导者角色。让Builder角色自己扮演指导者与建造者双重角色。结构图如下:

建造者角色代码如下:

1publicclassBuilder
2{
3privateProductproduct=newProduct();
4
5publicvoidBuildPartA()
6{
7//
8}
9
10publicvoidBuildPartB()
11{
12//
13}
14
15publicProductGetResult()
16{
17returnproduct;
18}
19
20publicvoidConstruct()
21{
22BuildPartA();
23BuildPartB();
24}
25}

客户程序:
1publicclassClient
2{
3privatestaticBuilderbuilder;
4
5publicstaticvoidMain()
6{
7builder=newBuilder();
8builder.Construct();
9Productproduct=builder.GetResult();
10}
11}

合并建造者角色和产品角色

建造模式失去抽象建造者角色和指导者角色后,可以进一步退化,从而失去具体建造者角色,此时具体建造者角色和产品角色合并,从而使得产品自己就是自己的建造者。这样做混淆了对象的建造者和对象本身,但是有时候一个产品对象有着固定的几个零件,而且永远只有这几个零件,此时将产品类和建造类合并,可以使系统简单易读。结构图如下:

实现要点

1、建造者模式主要用于“分步骤构建一个复杂的对象”,在这其中“分步骤”是一个稳定的算法,而复杂对象的各个部分则经常变化。

2、产品不需要抽象类,特别是由于创建对象的算法复杂而导致使用此模式的情况下或者此模式应用于产品的生成过程,其最终结果可能差异很大,不大可能提炼出一个抽象产品类。
3、创建者中的创建子部件的接口方法不是抽象方法而是空方法,不进行任何操作,具体的创建者只需要覆盖需要的方法就可以,但是这也不是绝对的,特别是类似文本转换这种情况下,缺省的方法将输入原封不动的输出是合理的缺省操作。

4、前面我们说过的抽象工厂模式(Abtract Factory)解决“系列对象”的需求变化,Builder模式解决“对象部分”的需求变化,建造者模式常和组合模式(Composite Pattern)结合使用。

效果

1、建造者模式的使用使得产品的内部表象可以独立的变化。使用建造者模式可以使客户端不必知道产品内部组成的细节。
2、每一个Builder都相对独立,而与其它的Builder无关。
3、可使对构造过程更加精细控制。

4、将构建代码和表示代码分开。

5、建造者模式的缺点在于难于应付“分步骤构建算法”的需求变动。

适用性

以下情况应当使用建造者模式:

1、需要生成的产品对象有复杂的内部结构。
2、需要生成的产品对象的属性相互依赖,建造者模式可以强迫生成顺序。
3、在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到。

应用场景

1、RTF文档交换格式阅读器。

2、.NET环境下的字符串处理StringBuilder,这是一种简化了的建造者模式。

3、……

总结

建造者模式的实质是解耦组装过程和创建具体部件,使得我们不用去关心每个部件是如何组装的。

分享到:
评论

相关推荐

    建造者模式【Builder Pattern】(一)问题提出

    在“BuilderPattern”这个压缩包中,可能包含了关于建造者模式的示例代码、解释文档或教程。这些资源可以帮助我们更好地理解建造者模式的实现和应用场景。通过研究这些内容,我们可以学习如何设计和使用建造者模式,...

    建造者模式【Builder Pattern】(二)问题改进

    建造者模式(Builder Pattern)是一种创建型设计模式,它允许我们分步骤构建复杂对象,而无需暴露构造过程的细节。这种模式将一个复杂的构建过程分解为一系列简单的步骤,使得构造过程可以有不同的解释,从而实现...

    建造者模式【Builder Pattern】(三)问题引申

    建造者模式(Builder Pattern)是一种创建型设计模式,它允许我们分步骤构建复杂对象,而无需暴露构造过程的细节。这种模式将一个复杂的构建过程分解为一系列简单的步骤,使得构造过程和表示细节可以独立变化。在...

    Java24种设计模式,Java24种设计模式,24种设计模式,学会了这24种设计模式,可以打遍天下无敌手,设计模式非常重要

    10、建造者模式BUILDER PATTERN 11、桥梁模式BRIDGE PATTERN 12、命令模式COMMAND PATTERN 13、装饰模式DECORATOR PATTERN 14、迭代器模式ITERATOR PATTERN 15、组合模式COMPOSITE PATTERN 16、观察者模式...

    java设计模式-建造者模式(Builder Pattern)

    在Java中,建造者模式(Builder Pattern)是一种创建型设计模式,它允许你分步骤地构建一个复杂对象。这个模式通过将构建过程和表示过程分离,使得同样的构建过程可以创建不同的表示。建造者模式特别适合用于创建...

    建造者模式【Builder Pattern】(一)问题改进

    建造者模式(Builder Pattern)是设计模式中的一种创建型模式,它允许我们分步骤构建复杂的对象,而无需暴露其构造过程。在实际的软件开发中,我们常常遇到需要创建具有多种构建方式或配置的对象,这时建造者模式就...

    [创建型模式]设计模式之建造者模式(Builder Pattern)

    【创建型模式】设计模式之建造者模式(Builder Pattern) 建造者模式(Builder Pattern)是设计模式中的一个创建型模式,它提供了一种方法来分步骤构造复杂的对象,使得构造过程和表示分离,使得同样的构建过程可以...

    建造者模式(Builder Pattern)原理图

    建造者模式是一种创建型设计模式,用于简化复杂对象的创建过程。以下是建造者模式的关键概念和步骤: 1. **分离复杂对象的构建和表示**:建造者模式将一个复杂对象的构建过程与其最终的表示形式分离开来。这样做的...

    设计模式之建造者Builder模式

    **建造者模式(Builder Pattern)**是软件设计模式中的一种,属于创建型模式。它将复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式通常用于那些需要大量构造参数的对象,通过...

    c++-设计模式之“建造者模式(Builder)”

    建造者模式(Builder Pattern)是一种创建型设计模式,允许使用多个简单的对象一步一步构建一个复杂的对象。它将对象的构建过程与表示分离,使得同样的构建过程可以创建不同的表示。 建造者模式的组成 产品...

    java实现建造者模式(Builder Pattern)

    java实现建造者模式(Builder Pattern) java实现建造者模式(Builder Pattern)是一种软件设计模式,旨在解决软件系统中创建复杂对象的问题。建造者模式可以将复杂对象的创建过程分解为多个简单的对象一步一步构建...

    设计模式之建造者模式代码示例

    建造者模式(Builder Pattern)是软件工程中一种用于创建对象的抽象工厂方法,它将复杂的构建过程分解为一系列步骤,使得构建过程可以独立于其表示进行。这种模式允许客户端使用相同的构建过程创建不同表现形式的...

    设计模式-建造者模式

    通过分析提供的文件名"NO4BuilderPattern",我们可以推测这可能是一个关于建造者模式的实例代码。在查看源码时,我们可以关注以下几点: 1. 产品类的定义及其组成部分。 2. 抽象建造者接口的实现,包括构建部件的...

    设计模式之建造者模式

    建造者模式(Builder Pattern)是设计模式中的一种创建型模式,它允许我们分步骤构建复杂的对象,通过将构造过程与对象本身分离,使得同样的构造过程可以创建不同的表示。这种模式常用于当创建对象的步骤复杂或者...

    建造者模式学习以及与工厂模式的区别

    建造者模式(Builder Pattern)是一种创建型设计模式,它提供了一种方法来分步骤构建复杂的对象,使得构建过程和表示分离。这种模式常用于当一个对象的构建过程复杂且需要多个步骤时,或者当我们希望同一个构建过程...

    建造者模式实例

    文件`BuilderPattern1`和`BuilderPattern`可能是示例代码或者进一步的解释,它们可能包含一个完整的建造者模式实现,包括产品类、抽象建造者、具体建造者和导演类的代码,以及如何在客户端使用这些类的例子。...

    设计模式例子,观察者模式,建造者模式

    在给定的压缩包文件中,"设计模式例子,观察者模式,建造者模式" 提到了两种重要的设计模式:观察者模式(Observer Pattern)和建造者模式(Builder Pattern)。下面我们将深入探讨这两种设计模式的概念、应用场景、...

    java 建造者模式

    建造者模式(Builder Pattern)是Java设计模式中的创建型模式...通过阅读和实践这个`BuilderPattern`压缩包中的内容,你可以更深入地理解和掌握建造者模式在Java中的应用及其优势,为你的编程生涯增添一份宝贵的技能。

    Java建造者模式源码

    还有时,建造者模式会被用来实现链式构建,即每个构建方法都返回Builder自身,使得调用者可以通过连缀方法来构建对象。 **建造者模式的优点:** 1. **封装性**:建造者模式将创建对象的复杂过程隐藏起来,使得...

    java 建造者模式 源码

    建造者模式(Builder Pattern)是设计模式中的一种创建型模式,它允许我们分步骤构建复杂的对象,而无需暴露构造过程。在Java中,这种模式常用于实现对象的组装过程,使得构建过程和表示分离,提高了代码的可读性...

Global site tag (gtag.js) - Google Analytics