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

 

建造者模式(Builder Pattern

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

Terrylee20051217

概述

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

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

意图

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

模型图

生活中的例子

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

实现过程图解

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

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

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

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

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

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

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

程序实现:

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

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

产品(套餐)类:

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

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

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

22        
23        /// <summary>
24        /// 显示食品清单
25        /// </summary>

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

程序实现:

 1using System;
 2
 3namespace KFC
 4{
 5    /// <summary>
 6    /// FoodManager类,即指导者
 7    /// </summary>

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

程序实现:

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

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

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

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

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

29        public abstract Food GetFood();
30    }

31}

32

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

 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

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

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

完整的客户程序:

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

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

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

另外一个例子

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

程序实现:

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

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

 14
 15/// <summary>
 16/// 具体建造者
 17/// </summary>

 18public class CApt:IHouse
 19{
 20    private bool mblnBackyard;
 21    private Hashtable Rooms;
 22    public CApt()
 23    {
 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()
 42    {
 43        return mblnBackyard;
 44    }

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

 49    public string  Description()
 50    {
 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())
 56        {
 57            strDescription = strDescription + "\n" + myEnumerator.Key + "\t" + ((CRoom)myEnumerator.Value).RoomName;
 58        }

 59        return strDescription;
 60    }

 61}

 62
 63/// <summary>
 64/// 具体建造者
 65/// </summary>

 66public class CSFH:IHouse
 67{
 68    private bool mblnBackyard;
 69    private Hashtable Rooms;
 70    public CSFH()
 71    {
 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()
100    {
101        return mblnBackyard;
102    }

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

107    public string  Description()
108    {
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())
114        {
115            strDescription = strDescription + "\n" + myEnumerator.Key + "\t" + ((CRoom)myEnumerator.Value).RoomName; 
116        }
      
117        return strDescription;
118    }

119}

120
121public interface IRoom
122{
123    string RoomName{get;set;}
124}

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

135        set 
136        {
137            mstrRoomName = value;
138        }

139    }

140}

141
142/// <summary>
143/// 指导者
144/// </summary>

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

153        else
154        {
155            return new CApt(); 
156        }

157    }

158}

159
160/// <summary>
161/// 客户程序
162/// </summary>

163public class Client
164{
165    static void Main(string[] args) 
166    {
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  {
 3   private ConcreteBuilder builder;
 4 
 5   public void Construct()
 6    {
 7     builder.BuildPartA();
 8     builder.BuildPartB();
 9   }

10 }

省略指导者角色

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

建造者角色代码如下:

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

 9 
10   public void BuildPartB()
11    {
12     //
13   }

14 
15   public Product GetResult()
16    {
17     return product;
18   }

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

25 }

客户程序:
 1 public class Client
 2  {
 3   private static Builder builder;
 4 
 5   public static void Main()
 6    {
 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
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
posted @ 2005-12-19 09:32 TerryLee 阅读(28068) 评论(56)  编辑 收藏 网摘 所属分类: [05]  架构与设计

  回复  引用  查看    
#1楼2005-12-29 15:32 | zitiger      
您的文章很好懂,谢谢.不过好像有些日子没写了,是不是最近太忙了?
  回复  引用  查看    
#2楼[楼主]2005-12-30 08:26 | Terrylee      
@zitiger

呵呵,最近忙着研究代码生成了

一直没顾得上

争取元旦期间出一篇设计模式的文章……

  回复  引用    
#3楼2006-06-13 09:49 | cclinux[未注册用户]
请问抽象工厂模式和建造者模式之间的异同
  回复  引用  查看    
#4楼2006-07-05 10:42 | 汪洋怡舟      
牛人一个
  回复  引用  查看    
#5楼[楼主]2006-07-05 10:53 | TerryLee      
@汪洋怡舟

呵呵,过奖了:)

  回复  引用    
#6楼2006-07-13 21:33 | sssss81[未注册用户]
路过
  回复  引用    
#7楼2006-07-13 21:35 | sssss81[未注册用户]
这文章写得好
  回复  引用  查看    
#8楼[楼主]2006-07-14 08:03 | TerryLee      
@sssss81

谢谢:-)

  回复  引用    
#9楼2006-07-21 11:48 | dhz8848[未注册用户]
大牛
  回复  引用    
#10楼2006-07-27 09:31 | xiaoqin[未注册用户]
你的buildHouse其实不是建造者模式,建造者模式的精华是分离产品构造,封装构造过程,但是你这里并没有封状出统一的构造过程,更象是工厂模式......
  回复  引用  查看    
#11楼2006-08-12 19:30 | Ring      
@xiaoqin
符合建造者模式的精髓!
作者把"统一的构造过程"放在构造函数中, 意思是一样的!

  回复  引用    
#12楼2006-08-21 17:18 | joyli[未注册用户]
我看你的第二个例子,house,应当是简单工厂模式吧!看了xiaoqin的回复,虽然是符合builder的概念但还是感觉到这个例子有些差强人意。不过还是很佩服,谢谢了。
Builder模式强调的是一步步创建对象,并通过相同的创建过程可以获得不同的结果对象

也就是说:每一步创建的对象都是复合对象的一部分。把construct用构造函数来代替,总感觉有些别扭。

  回复  引用    
#13楼2006-08-22 09:34 | cosmic[未注册用户]
@Ring
我认为这不能算一个Builder模式。
这里“统一的构造过程”是被放在了所有ConcreteBuilder的构造函数中,而非独立在Director中(或者放到抽象基类中也算),是事实上“不统一的构造过程”。

  回复  引用    
#14楼2006-11-29 09:55 | tom[匿名][未注册用户]
很生动,期待更好的文章!

  回复  引用  查看    
#15楼[楼主]2006-11-29 21:32 | TerryLee      
@tom[匿名]
:)

  回复  引用  查看    
#16楼2006-12-07 23:53 | 小芒果先生      
可以说一下:“建造者模式常和组合模式(Composite Pattern)如何结合使用”吗?
对于建造者模式常和组合模式(Composite Pattern)结合使用,好像抓到了点什么,但又比较迷糊。希望楼主再给一个例子。
谢谢。佩服楼主.

  回复  引用  查看    
#17楼2007-01-12 20:54 | YaziMyWife      
没有分清楚抽象工厂模式和这个建造者模式
  回复  引用  查看    
#18楼[楼主]2007-01-15 08:38 | TerryLee      
@YaziMyWife
这两者还是有些区别,侧重点不太一样

  回复  引用  查看    
#19楼2007-01-30 16:53 | YaziMyWife      
可不可以这样理解
抽象工厂处于建造者模式的下面.
抽象工厂主要是创建具体的对象而建造者模式是把这些对象构建成更加复杂的对象.
抽象工厂主要是建立简单的对象而创建者模式主要是建立相对复杂的对象

  回复  引用  查看    
#20楼2007-01-30 16:54 | YaziMyWife      
也可以这么说抽象工厂主要是建立零件而创建者模式主要是用来创建"产品",不知道我这样一来理解对吗??
  回复  引用    
#21楼2007-02-07 08:58 | [匿名] [未注册用户]
好东西,顶
  回复  引用    
#22楼2007-04-05 18:04 | jerrybi[未注册用户]
好! 早看到这篇就不买书了 ~~ 后悔
  回复  引用    
#23楼2007-04-12 16:14 | saleh[未注册用户]
简单明了!
以前看其他的文章, 连个大概都不清.
呵呵..

  回复  引用    
#24楼2007-05-14 19:09 | runner[未注册用户]


  回复  引用  查看    
#25楼2007-06-07 14:18 | 何时若愚      
1使用了模板模式
2使用了迭代器
3不错

  回复  引用    
#26楼2007-08-16 16:27 | 滋心[未注册用户]
感谢给我们带来了那么好的教程,但是
肯德基的例子我有一些疑惑,Builder类,即抽象建造者类,构造套餐由“FoodManager类,即指导者”来创建是否会更好一些,否则,我现在看不明白“指导者”有什么存在的意义?

  回复  引用    
#27楼2007-08-16 16:30 | 滋心[未注册用户]
我是看到了建房子的例子才明白“指导者”的作用是创建不同的产品,不知我的理解对吗?谢谢
  回复  引用    
#28楼2007-09-14 12:40 | hfhgui[未注册用户]
谢谢!
  回复  引用  查看    
#29楼2007-11-29 17:36 | RanKang      
能不能不举吃的 例子啊,比如KFC,看着都看不下去了...饿了...:)
  回复  引用  查看    
#30楼2008-04-15 11:55 | 隐姓埋名      
晕 有点没搞懂 抽象工厂 跟 建造者的异议~
  回复  引用  查看    
#31楼2008-04-28 13:37 | AaronHu      
现在正一篇一篇学习,代码练习。
一个公司可以经常请教你,可惜你太忙。

  回复  引用  查看    
#32楼2008-06-03 16:13 | 小眼睛老鼠      
我看了第一个例子和后面整合的部分
觉得分析的非常透彻
由小到大的刨析
不过还有有理解不透的地方
回家后继续理解

以前一直都没法分清设计时的设计粒度
看到楼主的分析问题的方法很像我看得一本重构的书的解决方法
一开始建立一个好的起点将一切打散不考虑外观的表现(宁可多几个类,也不好把逻辑搞乱)
为之后整合时候的的重构整合几个类打下了一个良好的基础

最后的结果看起来和最初看起来已经是2种表现方式了
不过内涵还是一样的
只不过最终是由一开始推导过来的

我对工厂模式和建造者模式的区别是这样理解不知道对不对
工厂模式封装的是个整体
而建造者模式封装的是整体里的一个步骤
就拿kfc来说也许美国的和中国的就存在价格和产品的不同
但是顾客在kfc里买套餐这个过程是不会变的

如果是上面这种情况
用来封装美国和中国的kfc营业的一套规则不同
这里就可以用工厂模式封装
而在这某套规则中(中国或者美国)的某个步骤的几种动作的情况通过建造者模式封装

非常感谢楼主的分享

  回复  引用  查看    
#33楼2008-09-17 13:11 | 贝贝(zbc)      
看了抽象工厂和建造者模式.(没有认真研究单件模式,因为是做网站应用程序,觉得似乎不大用得上)

体会这么一点:封装变化,抽出不变的部分形成体系(步骤,类),要修改时只需修改(重构)出一个新的类来适应变化,目的就是解耦.

还有面向接口编程,至此我觉得这是设计模式的首要任务.



有句话叫什么来着,很好很强大.

  回复  引用  查看    
#34楼[楼主]2008-10-08 11:14 | TerryLee      
@贝贝(zbc)
一语中的,抽象出不变的部分!

  回复  引用  查看    
#35楼2008-10-29 01:25 | Zero.Li      
从单件模式看到建造者模式,收获很大,感谢楼主。
楼上很多人疑问工厂模式和建造者模式,我也说下我的理解。
两个模式从行为上都是创建对象,工厂模式适应不同类型的对象创建,而建造者模式能够微调同一类型对象从而创建对象的目的。
如果运用到数据库实体中,工厂模式用于创建不同表的实体,如Table1,Table2,Table3等,建造者模式可以创建根据不同表所关联的类似于视图的实体,比如Table1组合Table2,Table2组合table3,或者Table1组合Table2组合Table3。

  回复  引用    
#36楼2008-10-30 14:09 | 王文斌[未注册用户]
你好,我最近正在学习设计模式,看到你的文章后,有点想法。建造者模式你这里给出的KFC的例子,感觉怎么好像模板模式呢。定义一个统一接口,然后2个套餐做不同实现。最后通过一个模板(依次调用4个方法),最后用动态工厂方法模式,通过录入结合配置文件返回具体实现给模板,然后模板执行生产。就像你Main里面做得一样。那么我就优点迷惑,什么时候用建造者,什么时候用模板好些?其实感觉都能够很好的支持开闭原则,期望指教。
  回复  引用  查看    
#37楼[楼主]2008-10-30 17:54 | TerryLee      
@王文斌
其实它们还是有区别的,建造者模式关注的是“对象创建”的过程,而模板方法关注的是行为!就这个例子来说,用哪种方法实现都没有问题,又或者可以结合它们来实现。另外,只要实现的优雅,也不用完全追求去符合某一个模式,那样反而有过度设计之嫌。

  回复  引用    
#38楼2008-10-31 10:53 | 王文斌[未注册用户]
受教了,谢谢回复。昨天又翻阅了一下Java与模式,里面也描述了建造者与模板方法模式的共通,确实是像你说的,感觉建造这就是模板方法的一个特例一样的东西,重点倾向与创建对象。谢谢。
  回复  引用  查看    
#39楼[楼主]2008-11-05 09:45 | TerryLee      
@王文斌
:)

  回复  引用  查看    
#40楼2008-11-10 15:08 | PatrickChen      
A Builder pattern is somewhat like an Abstract Factory pattern in that both return classes made up of a number of methods and objects. The main difference is that while the Abstract Factory returns a family of related classes, the Builder constructs a complex object step by step, depending on the data presented to it.
  回复  引用  查看    
#41楼2008-12-14 13:12 | pillow      
builder模式侧重于创建一个过程复杂对象。抽象工厂侧重于创建一系列相关对象。
如果和抽象工厂相比的话。builder的复杂对象是由过程可能有序可能无序组成的。抽象工厂有具体工厂组成,具体工厂由一系列相关对象组成。

  回复  引用  查看    
#42楼2008-12-31 10:44 | Fengdesudu      
非常不错,感谢啊
  回复  引用  查看    
#43楼[楼主]2009-01-04 11:19 | TerryLee      
@Fengdesudu
客气了,谢谢支持:)

  回复  引用  查看    
#44楼2009-01-05 16:55 | 森林木      
感觉builder 和AF 从类的关系上看本质上没什么不同:都是不同的factory/builer 创建不同的一系列产品,只是从不同的视角看过去会有些许差别,两者侧重点不一样,但实际运用时没必要分那么清楚。
  回复  引用  查看    
#45楼2009-01-13 18:09 | Alex.Li      
Builder的特质是创建同类对象的不同表象,而工厂是用于创建不同类对象。
Builder封装了对象构建过程的算法,这个算法不一定是一个简单过程,也可能是循环,分支,或更复杂的算法。在实际应用中如果要用到Builder模式往往对象的构成算法是比较复杂的。
一个图形的伪代码的例子:
class Shape:{
//几何图形类
包含点集合,线集,面集
}

class Builder1:IBuilderRoot
{
Shape m_shape;
drawPoint(); //绘制一般点
drawLine();//绘制一般线
drawPoly();//绘制一般面
}

class Builder2:IBuilderRoot
{
Shape m_shape;
drawPoint(); //绘另一种点,如半径为x 的球
drawLine();//绘制虚线
drawPoly();//绘制网状面
}

class BallDirector:IDirector
{
Construct(){
While(最后一个点?){
//绘制球体的算法,根据方程得当前点的坐标并绘制
builder.drawPoint();
//和三个点的连线
builder.drawLine();
builder.drawLine();
builder.drawLine();
//绘制一个三角面()
builder.drawPoly();
}
}
}

class CubeDirector:IDirector
{
Construct(){
//方体算法,得到四个顶点
builder.drawPoint();
builder.drawPoint();
builder.drawPoint();
builder.drawPoint();
//连线
builder.drawLine();
...
//绘面
builder.drawPoly();
...
}
}

client代码
Run(){
Builder1 b1=new Builder1();//一般球builder
Builder2 b2=new Builder2();//球顶点-网状球builder
BallDirector d1=new BallDirector();
d1.builder=b1;
Shape=d1.Construct();//绘制一个一般的球
d1.builder=b2;
Shape=d1.Construct();//绘制一个球顶点-网状球
CubeDirector d2=new CubeDirector ();
d2. builder=b1;
Shape=d2. Construct()//绘制一个一般的方体
}

不同的builder可以共享一个Director的算法来构建对象,不同的Director也可以共享同一个builder来共享对象构成的细节。Builder最大程度的重用了对象的组建算法和对象细节构成的算法。

  回复  引用    
#46楼2009-03-04 17:28 | vhnuuh
@PatrickChen
开卷有益的文章,刚开始还是有些不懂,看了下面的回复再想一下就豁然开朗了。
谢谢楼主的文章!
“returns a family of related classes”是不是可以理解为:返回基于相同接口的很多类?

  回复  引用    
#47楼2009-03-25 16:16 | 兵工厂→枪手
建造者模式是不是就是把其中创建的过程给封装起来,客户端可以直接就能获取到需要的信息。
  回复  引用    
#48楼2009-03-25 16:22 | 兵工厂→枪手
还有就是如果KFC的套餐中需要加鸡翅,建造者模式如何应对这样的变化?
  回复  引用  查看    
#49楼2009-03-30 15:19 | 徐培华      
这篇文章看起来有些费劲,看不懂。
  回复  引用  查看    
#50楼2009-04-12 19:29 | window5549-accp      
把敲好的例子传一个出来才好呀。真是的!!!!!!!!!!!!!!!!!!!!!!B视
  回复  引用    
#51楼2009-05-18 08:33 | 尐姐、愛涐么
看你的文章长大的
  回复  引用  查看    
#52楼[楼主]2009-05-18 11:11 | TerryLee      
@尐姐、愛涐么
:)

  回复  引用  查看    
#53楼2009-06-14 10:50 | 会长      
好!
  回复  引用    
#54楼2009-06-25 11:35 | 光庸
总决的第二个列子很牵强,难道是我学的太死板。CDirector 没体现出Builde过程,但是你又把builde的过程封装到每个具体建造者中。是不是只要把builde 的过程封装起来就行,至于在那里封装 就可以看情况而定了??



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 299878




相关文章:

相关链接: