什么建造者模式(Builder Pattern)?
流程稳定,实现复杂,将实现过程封装隔离的设计模式.
包含对象 操纵(Client) 指导者(Director) 创建者(Builder) 产出者(Product)
如下图:
通过上图的分析大致 他们的关系就显而易见了.
下面一个小例子就能说明 这个关系
公司小王想要加薪 所以就给领导张总提出了加薪的要求,张总看小王的表现让财务小陈上添加50000元的薪水,小王高高兴兴的多得到了50000的薪水
这个个过程就可以用建造者的设计模式来解释.
操纵者发起人是 小王(上图中的Client)
指导者是 张总(上图中的Director)
执行者是 财务小陈 (上图中的Builder)
产品是 50000的薪水(上图中的Product)
满足这个设计模式的条件了吗?
执行过程相对稳定-->加薪的过程就是这样 提出申请 领导点头 财务操作
实现复杂-->提出申请 领导根据申请人的实际情况,工作现状 做出不同的态度和反应,如:加薪1块 或者是1000000块
另:
用户去买KFC的过程:
客户端:顾客。想去买一套套餐(这里面包括汉堡,可乐,薯条),可以有1号和2号两种套餐供顾客选择。
指导者角色:收银员。知道顾客想要买什么样的套餐,并告诉餐馆员工去准备套餐。
建造者角色:餐馆员工。按照收银员的要求去准备具体的套餐,分别放入汉堡,可乐,薯条等。
产品角色:最后的套餐,所有的东西放在同一个盘子里面。
以上例子也是同一个道理
实现代码:
1
using
System;
2
using
System.Configuration;
3
using
System.Reflection;
4
5
namespace
KFC
6
{
7 ///
8 /// Client 类
9 ///
10 public class Client
11 {
12 public static void Main(string[] args)
13 {
//当你在点餐的时候 就会出现一个收银员 所以创建了一个 指导者对象
14 FoodManager foodmanager = new FoodManager();
15
16 Builder instance;
17
18 Console.WriteLine("Please Enter Food No:");
19
20 string No = Console.ReadLine();
21
22 string foodType = ConfigurationSettings.AppSettings["No"+No];
23
24 instance = (Builder)Assembly.Load("KFC").CreateInstance("KFC." + foodType);
25 //根据你的需求 指导者给创造者做出了安排 告诉了员工 客户的需求是什么
26 foodmanager.Construct(instance);
27 }
28 }
29}
30
产品(套餐)类:(该类中的ADD方法个人认为不太正确,add方法应该放到Builder类中,这是Builder对象的一个行为,但此处还是按照原作者的实现方式 将add放到了food中...同样show方法也该放懂啊FoodManager中,food 就应该是一个实体,放的是价格名称什么的)
1using System;
2
using System.Collections;
3
4
namespace KFC
5
{
6
///
7 /// Food类,即产品类
8 ///
9
public
class Food
10
{
11 Hashtable food =
new Hashtable();
12
13
///
14 /// 添加食品
15 ///
16 /// 食品名称
17 /// 价格
18
public
void Add(
string strName,
string Price)
19
{
20 food.Add(strName,Price);
21 }
22
23
///
24 /// 显示食品清单
25 ///
26
public
void Show()
27
{
28 IDictionaryEnumerator myEnumerator = food.GetEnumerator();
29 Console.WriteLine("Food List:");
30 Console.WriteLine("------------------------------");
31
string strfoodlist = "";
32
while(myEnumerator.MoveNext())
33
{
34 strfoodlist = strfoodlist + "\n\n" + myEnumerator.Key.ToString();
35 strfoodlist = strfoodlist + ":\t" +myEnumerator.Value.ToString();
36 }
37 Console.WriteLine(strfoodlist);
38 Console.WriteLine("\n------------------------------");
39 }
40 }
41 }
42
2.指导者通知建造器。收银员(指导者)告知餐馆员工准备套餐。这里我们准备套餐的顺序是:放入汉堡,可乐倒入杯中,薯条放入盒中,并把这些东西都放在盘子上。这个过程对于普通套餐和黄金套餐来说都是一样的,不同的是它们的汉堡,可乐,薯条价格不同而已。如时序图红色部分所示:
程序实现:
1
using System;
2
3
namespace KFC
4
{
5
///
6 /// FoodManager类,即指导者
7 ///
8
public
class FoodManager
9
{
10
public
void Construct(Builder builder)
11
{
12 builder.BuildHamb();
13
14 builder.BuildCoke();
15
16 builder.BuildChip();
17 }
18 }
19 }
20
3.建造者处理指导者的要求,并将部件添加到产品中。餐馆员工(建造者)按照收银员要求的把对应的汉堡,可乐,薯条放入盘子中。这部分是建造者模式里面富于变化的部分,因为顾客选择的套餐不同,套餐的组装过程也不同,这步完成产品对象的创建工作。
程序实现:
1
using System;
2
3
namespace KFC
4
{
5
///
6 /// Builder类,即抽象建造者类,构造套餐
7 ///
8
public
abstract
class Builder
9
{
10
///
11 /// 添加汉堡
12 ///
13
public
abstract
void BuildHamb();
14
15
///
16 /// 添加可乐
17 ///
18
public
abstract
void BuildCoke();
19
20
///
21 /// 添加薯条
22 ///
23
public
abstract
void BuildChip();
24
25
///
26 /// 返回结果
27 ///
28 /// 食品对象
29
public
abstract Food GetFood();
30 }
31 }
32
1
using System;
2
3
namespace KFC
4
{
5
///
6 /// NormalBuilder类,具体构造者,普通套餐
7 ///
8
public
class NormalBuilder:Builder
9
{
10
private Food NormalFood =
new Food();
11
12
public
override
void BuildHamb()
13
{
14 NormalFood.Add("NormalHamb","¥10.50");
15 }
16
17
public
override
void BuildCoke()
18
{
19 NormalFood.Add("CokeCole","¥4.50");
20 }
21
22
public
override
void BuildChip()
23
{
24 NormalFood.Add("FireChips","¥2.00");
25 }
26
27
public
override Food GetFood()
28
{
29
return NormalFood;
30 }
31
32 }
33 }
34
1
using System;
2
3
namespace KFC
4
{
5
///
6 /// GoldBuilder类,具体构造者,黄金套餐
7 ///
8
public
class GoldBuilder:Builder
9
{
10
private Food GoldFood =
new Food();
11
12
public
override
void BuildHamb()
13
{
14 GoldFood.Add("GoldHamb","¥13.50");
15 }
16
17
public
override
void BuildCoke()
18
{
19 GoldFood.Add("CokeCole","¥4.50");
20 }
21
22
public
override
void BuildChip()
23
{
24 GoldFood.Add("FireChips","¥3.50");
25 }
26
27
public
override Food GetFood()
28
{
29
return GoldFood;
30 }
31
32 }
33 }
34
4.客户从建造者检索产品。从餐馆员工准备好套餐后,顾客再从餐馆员工那儿拿回套餐。这步客户程序要做的仅仅是取回已经生成的产品对象,如时序图中红色部分所示。
完整的客户程序:
1
using System;
2
using System.Configuration;
3
using System.Reflection;
4
5
namespace KFC
6
{
7
///
8 /// Client 类
9 ///
10
public
class Client
11
{
12
public
static
void Main(
string[] args)
13
{
14 FoodManager foodmanager =
new FoodManager();
15
16 Builder instance;
17
18 Console.WriteLine("Please Enter Food No:");
19
20
string No = Console.ReadLine();
21
22
string foodType = ConfigurationSettings.AppSettings["No"+No];
23
24 instance = (Builder)Assembly.Load("KFC").CreateInstance("KFC." + foodType);
25
26 foodmanager.Construct(instance);
27
28 Food food = instance.GetFood();
29 food.Show();
30
31 Console.ReadLine();
32 }
33 }
34 }
35
通过分析不难看出,在这个例子中,在准备套餐的过程是稳定的,即按照一定的步骤去做,而套餐的组成部分则是变化的,有可能是普通套餐或黄金套餐等。这个变化就是建造者模式中的“变化点“,就是我们要封装的部分。
实现要点
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、 ……
总结
建造者模式的实质是解耦组装过程和创建具体部件,使得我们不用去关心每个部件是如何组装的。