建造者模式(Builder Pattern)

一、什么是建造者模式

意图:

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

模型图:

 

 

二、建造者模式实例

需求:这种模式用于快餐店制作儿童餐。典型的儿童餐包括一个主食,一个辅食,一杯饮料和一个玩具(例如汉堡、炸鸡、可乐和玩具车)。这些在不同的儿童餐中可以是不同的,但是组合成儿童餐的过程是相同的。无论顾客点的是汉堡,三名治还是鸡肉,过程都是一样的。柜台的员工直接把主食,辅食和玩具放在一起。这些是放在一个袋子中的。饮料被倒入杯中,放在袋子外边。这些过程在相互竞争的餐馆中是同样的。

示意图如下:

  • 客户端:顾客。想去买一套套餐(这里面包括汉堡,可乐,薯条),可以有1号和2号两种套餐供顾客选择。
  • 指导者角色:收银员。知道顾客想要买什么样的套餐,并告诉餐馆员工去准备套餐。
  • 建造者角色:餐馆员工。按照收银员的要求去准备具体的套餐,分别放入汉堡,可乐,薯条等。
  • 产品角色:最后的套餐,所有的东西放在同一个盘子里面。

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

程序实现如下:

产品(套餐)类:

 1 //产品套餐类
 2 public class Food
 3 {
 4     Hashtable foodList = new Hashtable();
 5 
 6     //添加套餐中含有的食物
 7     public void Add(string name, string price)
 8     {
 9         this.foodList.Add(name, price);
10     }
11 
12     //显示套餐中的产品
13     public void Show()
14     {
15         IDictionaryEnumerator myEnumerator = foodList.GetEnumerator();
16         Console.WriteLine("Food List");
17         Console.WriteLine("==============================");
18 
19         string strfoodlist = "";
20         while (myEnumerator.MoveNext())
21         {
22             strfoodlist = strfoodlist + "\n" + myEnumerator.Key.ToString();
23             strfoodlist = strfoodlist + ":\t" + myEnumerator.Value.ToString();
24         }
25 
26         Console.WriteLine(strfoodlist);
27         Console.WriteLine("\n------------------------------");
28     }
29 }

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

程序实现:

 1 //营业员(指导者角色)
 2 public class FoodManager
 3 {
 4     public void Construct(FoodBuilder builder)
 5     {
 6         builder.BuildHumb();
 7 
 8         builder.BuildCoke();
 9 
10         builder.BuildChips();
11     }
12 }

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

程序实现:

 1 public abstract class FoodBuilder
 2 {
 3     public abstract void BuildHumb();
 4 
 5     public abstract void BuildCoke();
 6 
 7     public abstract void BuildChips();
 8 
 9     public abstract Food GetFood();
10 }
 1 //具体构造者(普通餐)
 2 public class NormalFood : FoodBuilder
 3 {
 4     private Food normalFood = new Food();
 5 
 6     public override void BuildHumb()
 7     {
 8         normalFood.Add("NormalHumb", "$2.00");
 9     }
10 
11     public override void BuildCoke()
12     {
13         normalFood.Add("SmallCoke", "$1.30");
14     }
15 
16     public override void BuildChips()
17     {
18         normalFood.Add("SmallChips", "$1.60");
19     }
20 
21     public override Food GetFood()
22     {
23         return normalFood;
24     }
25 }
26 
27 //具体构造者(黄金套餐)
28 public class GoldenFood : FoodBuilder
29 {
30     private Food goldenFood = new Food();
31 
32     public override void BuildHumb()
33     {
34         goldenFood.Add("GoldenHumb", "$3.00");
35     }
36 
37     public override void BuildCoke()
38     {
39         goldenFood.Add("BigCoke", "$1.80");
40     }
41 
42     public override void BuildChips()
43     {
44         goldenFood.Add("BigChips", "$1.90");
45     }
46 
47     public override Food GetFood()
48     {
49         return goldenFood;
50     }
51 }

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

完整的客户程序:

 1 public class Client
 2 {
 3     public static void Main(string[] args)
 4     {
 5         FoodManager manager = new FoodManager();
 6         FoodBuilder builder = new GoldenFood();
 7 
 8         manager.Construct(builder);
 9 
10         Food goldenFood = builder.GetFood();
11         goldenFood.Show();
12 
13         Console.Read();
14     }
15 
16 }

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

 

 

三、建造者模式的效果

  • 建造者模式的使用使得产品的内部表象可以独立的变化。使用建造者模式可以使客户端不必知道产品内部组成的细节
  • 每一个Builder都相对独立,而与其它的Builder无关。
  • 可使对构造过程更加精细控制。
  • 将构建代码和表示代码分开。
  • 建造者模式的缺点在于难于应付“分步骤构建算法”的需求变动。

 

 

四、建造者模式的适用性

  • 需要生成的产品对象有复杂的内部结构。
  • 需要生成的产品对象的属性相互依赖,建造者模式可以强迫生成顺序。
  • 在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到。
posted @ 2012-04-26 15:53  技术勇者  阅读(1081)  评论(1编辑  收藏  举报