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

简介: 建造者模式(Builder Pattern) ——.NET设计模式系列之四 Terrylee,2005年12月17日 概述 在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法确相对稳定。

建造者模式(Builder Pattern

——.NET设计模式系列之四

Terrylee20051217

概述

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

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

意图

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

模型图

生活中的例子

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

实现过程图解

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

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

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

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

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

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

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

程序实现:

 1 using  System;
 2 using  System.Configuration;
 3 using  System.Reflection;
 4
 5 namespace  KFC
 6 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif {
 7img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    /// <summary>
 8    /// Client 类
 9    /// </summary>

10    public class Client
11img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
12        public static void Main(string[] args)
13img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
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

产品(套餐)类:

 1 using  System;
 2 using  System.Collections;
 3
 4 namespace  KFC
 5 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif {
 6img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    /// <summary>
 7    /// Food类,即产品类
 8    /// </summary>

 9    public class Food
10img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
11        Hashtable food = new Hashtable();
12        
13img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        /// <summary>
14        /// 添加食品
15        /// </summary>
16        /// <param name="strName">食品名称</param>
17        /// <param name="Price">价格</param>

18        public void Add(string strName,string Price)
19img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
20            food.Add(strName,Price);
21        }

22        
23img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        /// <summary>
24        /// 显示食品清单
25        /// </summary>

26        public void Show()
27img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
28            IDictionaryEnumerator myEnumerator  = food.GetEnumerator();
29            Console.WriteLine("Food List:");
30            Console.WriteLine("------------------------------");
31            string strfoodlist = "";
32            while(myEnumerator.MoveNext())
33img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif            {
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 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif {
 5img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    /// <summary>
 6    /// FoodManager类,即指导者
 7    /// </summary>

 8    public class FoodManager
 9img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
10        public void Construct(Builder builder)
11img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
12            builder.BuildHamb();
13
14            builder.BuildCoke();
15
16            builder.BuildChip();
17        }
    
18    }

19}

20

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

程序实现:

 1 using  System;
 2
 3 namespace  KFC
 4 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif {
 5img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    /// <summary>
 6    /// Builder类,即抽象建造者类,构造套餐
 7    /// </summary>

 8    public abstract class Builder
 9img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {    
10img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        /// <summary>
11        /// 添加汉堡
12        /// </summary>

13        public abstract void BuildHamb();
14        
15img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        /// <summary>
16        /// 添加可乐
17        /// </summary>

18        public abstract void BuildCoke();
19        
20img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        /// <summary>
21        /// 添加薯条
22        /// </summary>

23        public abstract void BuildChip();
24        
25img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        /// <summary>
26        /// 返回结果
27        /// </summary>
28        /// <returns>食品对象</returns>

29        public abstract Food GetFood();
30    }

31}

32

 1 using  System;
 2
 3 namespace  KFC
 4 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif {
 5img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    /// <summary>
 6    /// NormalBuilder类,具体构造者,普通套餐
 7    /// </summary>

 8    public class NormalBuilder:Builder
 9img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
10        private Food NormalFood = new Food();
11
12        public override void BuildHamb()
13img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
14            NormalFood.Add("NormalHamb","¥10.50");
15        }

16        
17        public override void BuildCoke()
18img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
19            NormalFood.Add("CokeCole","¥4.50");
20        }

21
22        public override void BuildChip()
23img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
24            NormalFood.Add("FireChips","¥2.00");
25        }

26
27        public override Food GetFood()
28img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
29            return NormalFood;
30        }

31
32    }

33}

34

 1 using  System;
 2
 3 namespace  KFC
 4 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif {
 5img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    /// <summary>
 6    /// GoldBuilder类,具体构造者,黄金套餐
 7    /// </summary>

 8    public class GoldBuilder:Builder
 9img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
10        private Food GoldFood = new Food();
11
12        public override void BuildHamb()
13img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
14            GoldFood.Add("GoldHamb","¥13.50");
15        }

16        
17        public override void BuildCoke()
18img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
19            GoldFood.Add("CokeCole","¥4.50");
20        }

21
22        public override void BuildChip()
23img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
24            GoldFood.Add("FireChips","¥3.50");
25        }

26
27        public override Food GetFood()
28img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
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 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif {
 7img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    /// <summary>
 8    /// Client 类
 9    /// </summary>

10    public class Client
11img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
12        public static void Main(string[] args)
13img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
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

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

另外一个例子

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

程序实现:

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

  8 public  interface  IHouse
  9 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif {
 10    bool GetBackyard();
 11    long NoOfRooms();
 12    string  Description();
 13}

 14
 15 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif /// <summary>
 16/// 具体建造者
 17/// </summary>

 18 public  class  CApt:IHouse
 19 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif {
 20    private bool mblnBackyard;
 21    private Hashtable Rooms;
 22    public CApt()
 23img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
 24        CRoom room;    
 25        Rooms = new Hashtable();
 26        room = new CRoom();
 27        room.RoomName = "Master Bedroom";
 28        Rooms.Add ("room1",room);
 29
 30        room = new CRoom();
 31        room.RoomName = "Second Bedroom";
 32        Rooms.Add ("room2",room);
 33
 34        room = new CRoom();
 35        room.RoomName = "Living Room";
 36        Rooms.Add ("room3",room);
 37        
 38        mblnBackyard = false;
 39    }

 40
 41    public bool GetBackyard()
 42img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
 43        return mblnBackyard;
 44    }

 45    public long NoOfRooms()
 46img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
 47        return Rooms.Count; 
 48    }

 49    public string  Description()
 50img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
 51        IDictionaryEnumerator myEnumerator  = Rooms.GetEnumerator();
 52        string strDescription;
 53        strDescription = "This is an Apartment with " + Rooms.Count + " Rooms "n";
 54        strDescription = strDescription + "This Apartment doesn't have a backyard "n";                        
 55        while (myEnumerator.MoveNext())
 56img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
 57            strDescription = strDescription + ""n" + myEnumerator.Key + ""t" + ((CRoom)myEnumerator.Value).RoomName;
 58        }

 59        return strDescription;
 60    }

 61}

 62
 63 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif /// <summary>
 64/// 具体建造者
 65/// </summary>

 66 public  class  CSFH:IHouse
 67 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif {
 68    private bool mblnBackyard;
 69    private Hashtable Rooms;
 70    public CSFH()
 71img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
 72        CRoom room;
 73        Rooms = new Hashtable();
 74
 75        room = new CRoom();
 76        room.RoomName = "Master Bedroom";
 77        Rooms.Add ("room1",room);
 78
 79        room = new CRoom();
 80        room.RoomName = "Second Bedroom";
 81        Rooms.Add ("room2",room);
 82
 83        room = new CRoom();
 84        room.RoomName = "Third Room";
 85        Rooms.Add ("room3",room);
 86        
 87        room = new CRoom();
 88        room.RoomName = "Living Room";
 89        Rooms.Add ("room4",room);
 90
 91        room = new CRoom();
 92        room.RoomName = "Guest Room";
 93        Rooms.Add ("room5",room);
 94
 95        mblnBackyard = true;
 96 
 97    }

 98
 99    public bool GetBackyard()
100img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
101        return mblnBackyard;
102    }

103    public long NoOfRooms()
104img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
105        return Rooms.Count;
106    }

107    public string  Description()
108img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
109        IDictionaryEnumerator myEnumerator  = Rooms.GetEnumerator();
110        string strDescription;
111        strDescription = "This is an Single Family Home with " + Rooms.Count + " Rooms "n";
112        strDescription = strDescription + "This house has a backyard "n"
113        while (myEnumerator.MoveNext())
114img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
115            strDescription = strDescription + ""n" + myEnumerator.Key + ""t" + ((CRoom)myEnumerator.Value).RoomName; 
116        }
      
117        return strDescription;
118    }

119}

120
121 public  interface  IRoom
122 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif {
123img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    string RoomName{get;set;}
124}

125
126 public  class  CRoom:IRoom
127 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif {
128    private string mstrRoomName;
129    public string RoomName
130img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
131        get
132img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
133            return mstrRoomName;
134        }

135        set 
136img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
137            mstrRoomName = value;
138        }

139    }

140}

141
142 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif /// <summary>
143/// 指导者
144/// </summary>

145 public  class  CDirector
146 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif {
147    public IHouse BuildHouse(bool blnBackyard)
148img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
149        if (blnBackyard)
150img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
151            return new CSFH();
152        }

153        else
154img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        {
155            return new CApt(); 
156        }

157    }

158}

159
160 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif /// <summary>
161/// 客户程序
162/// </summary>

163 public  class  Client
164 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif {
165    static void Main(string[] args) 
166img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
167        CDirector objDirector = new CDirector();
168        IHouse objHouse;
169
170        string Input = Console.ReadLine();
171        objHouse = objDirector.BuildHouse(bool.Parse(Input));
172    
173        Console.WriteLine(objHouse.Description());
174        Console.ReadLine();
175    }

176}

177
178

建造者模式的几种演化

省略抽象建造者角色

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

指导者代码如下:

 1   class  Director
 2 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif   {
 3   private ConcreteBuilder builder;
 4 
 5   public void Construct()
 6img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
 7     builder.BuildPartA();
 8     builder.BuildPartB();
 9   }

10 }

省略指导者角色

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

建造者角色代码如下:

 1   public  class  Builder
 2 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif   {
 3   private Product product = new Product();
 4 
 5   public void BuildPartA()
 6img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    
 7     //
 8   }

 9 
10   public void BuildPartB()
11img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
12     //
13   }

14 
15   public Product GetResult()
16img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
17     return product;
18   }

19 
20   public void Construct()
21img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
22     BuildPartA();
23     BuildPartB();
24   }

25 }

客户程序:
 1   public  class  Client
 2 img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif   {
 3   private static Builder builder;
 4 
 5   public static void Main()
 6img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    {
 7     builder = new Builder();
 8     builder.Construct();
 9     Product product = 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、   ……

总结

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

______________________________________________________________________________________

源程序下载:/Files/Terrylee/BuilderPattern.rar

参考资料:

Java与设计模式》阎宏

《设计模式(中文版)》

DesignPatternsExplained

作者: TerryLee
出处: http://terrylee.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
目录
相关文章
|
2月前
|
设计模式 算法
设计模式--建造者模式 builder
这篇文章通过一个电脑购买的例子,详细解释了建造者模式的四个角色(产品类、抽象构建者、实体构建类和指导者类),并提供了相应的代码实现,阐述了建造者模式在设计复杂对象时的应用和优势。
设计模式--建造者模式 builder
|
2月前
|
设计模式
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
这篇文章详细解释了工厂模式,包括简单工厂、工厂方法和抽象工厂三种类型。每种模式都通过代码示例展示了其应用场景和实现方法,并比较了它们之间的差异。简单工厂模式通过一个工厂类来创建各种产品;工厂方法模式通过定义一个创建对象的接口,由子类决定实例化哪个类;抽象工厂模式提供一个创建相关或依赖对象家族的接口,而不需要明确指定具体类。
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
|
2月前
|
设计模式 算法 Java
Java设计模式-建造者模式(6)
Java设计模式-建造者模式(6)
|
2月前
|
设计模式 Java
设计模式--适配器模式 Adapter Pattern
这篇文章介绍了适配器模式,包括其基本介绍、工作原理以及类适配器模式、对象适配器模式和接口适配器模式三种实现方式。
|
3月前
|
设计模式 XML 存储
【四】设计模式~~~创建型模式~~~建造者模式(Java)
文章详细介绍了建造者模式(Builder Pattern),这是一种创建型设计模式,用于将复杂对象的构建与其表示分离,允许分步骤创建一个复杂的对象而无需指定其内部的具体构造细节。通过定义抽象建造者、具体建造者、指挥者和产品角色,建造者模式允许通过相同的构建过程创建不同的产品表示,提高了系统的灵活性和扩展性。
|
4月前
|
设计模式 JavaScript
js设计模式【详解】—— 建造者模式
js设计模式【详解】—— 建造者模式
44 0
|
5月前
|
设计模式
设计模式-05建造者模式(Builder Pattern)
设计模式-05建造者模式(Builder Pattern)
|
5月前
|
设计模式 算法 索引
程序技术好文:设计模式之美:Builder(生成器)
程序技术好文:设计模式之美:Builder(生成器)
|
5月前
|
设计模式 Java
Java设计模式:建造者模式之经典与流式的三种实现(四)
Java设计模式:建造者模式之经典与流式的三种实现(四)
|
2月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。

热门文章

最新文章