好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

步步为营 .NET 设计模式学习笔记 十、Builder(建造者模式)

步步为营 .NET 设计模式学习笔记 十、Builder(建造者模式)

概述  

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

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

意图  

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

<Design Pattern>Builder模型图

通俗讲解:Builder模式的理解

建造者(Builder)角色:给出一个抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此接口独立于应用程序的商业逻辑。模式中直接创建产品对象的是具体建造者(ConcreteBuilder)角色。具体建造者类必须实现这个接口所要求的方法:一个是建造方法,另一个是结果返还方法。

具体建造者(Concrete Builder)角色:担任这个角色的是于应用程序紧密相关的类,它们在应用程序调用下创建产品实例。这个角色主要完成的任务包括:

实现Builder角色提供的接口,一步一步完成创建产品实例的过程。 在建造过程完成后,提供产品的实例。

指导者(Director)角色:担任这个角色的类调用具体建造者角色以创建产品对象。导演者并没有产品类的具体知识,真正拥有产品类的具体知识的是具体建造者对象。

产品(Product)角色:产品便是建造中的复杂对象。

指导者角色是于客户端打交道的角色。导演者角色将客户端创建产品的请求划分为对各个零件的建造请求,再将这些请求委派给具体建造者角色。具体建造者角色是做具体建造工作的,但却不为客户端所知。


简单地说,就好象我要一座房子住,可是我不知道怎么盖(简单的砌墙,层次较低),也不知道怎么样设计(建几个房间,几个门好看,层次较高), 于是我需要找一帮民工,他们会砌墙,还得找个设计师,他知道怎么设计,我还要确保民工听设计师的领导,而设计师本身也不干活,光是下命令,这里砌一堵墙,这里砌一扇门,这样民工开始建设,最后,我可以向民工要房子了。在这个过程中,设计师是什么也没有,除了他在脑子里的设计和命令,所以要房子也是跟民工要,记住了! 
就象国内好多企业上erp一样,上erp,首先得找软件公司呀,找到软件公司后,软件公司说,我只知道怎么写软件,就知道怎么实现,不清楚整个erp的流程。好,那我们还得找一个咨询公司,好,找到德勤了,德勤说好,我要软件怎么做,软件公司怎么做,我就能保证软件能为你们提供erp系统了。

示例用例图:

汽车的生产其实可以看作是一个建造者模式,大众生产Audi和Satana两种轿车,我们用例设计如下:

代码设计:

先创建 Car.cs:

01 public   class   Car

02 {

03      private   string   engine;

04      public   string   Engine

05      {

06          get   {  return   engine; }

07          set   { engine = value; }

08      }

09      private   string   gearing;

10      public   string   Gearing

11      {

12          get   {  return   gearing; }

13          set   { gearing = value; }

14      }

15      private   string   brake;

16      public   string   Brake

17      {

18          get   {  return   brake; }

19          set   { brake = value; }

20      }

21  

22      public   string   ShowInfo()

23      {

24          StringBuilder strBuilder =  new   StringBuilder();

25          strBuilder.AppendLine( "轿车配置如下:" );

26          strBuilder.AppendFormat( "发动机是:{0} \n" , Engine);

27          strBuilder.AppendFormat( "传动系是:{0} \n" , Gearing);

28          strBuilder.AppendFormat( "制动系是:{0} \n" , Brake);

29          return   strBuilder.ToString();

30      }

31  

32 }

然后创建BuildCar.cs:

01 public   abstract   class   BuildCar

02   {

03      private   string   name;

04      public   string   Name

05      {

06          get   {  return   name; }

07          set   { name = value; }

08      }

09      private   Car newCar;

10      public   Car NewCar

11      {

12          get   {  return   newCar; }

13          set   { newCar = value; }

14      }

15  

16      public   BuildCar()

17      {

18          newCar =  new   Car();

19      }

20      public   abstract   void   BuildEngine();

21      public   abstract   void   BuildGearing();

22      public   abstract   void   BuildBrake();

23   }

再创建Audi.cs:

01 public    class   Audi:BuildCar

02   {

03       public   override   void   BuildEngine()

04       {

05           NewCar.Engine =  "V型12缸发动机" ;

06       }

07  

08       public   override   void   BuildGearing()

09       {

10           NewCar.Gearing =  "四轮驱动(4WD)" ;

11       }

12  

13       public   override   void   BuildBrake()

14       {

15           NewCar.Brake =  "电磁式" ;

16       }

17       public   Audi()

18       {

19           Name =  "Audi A8" ;

20       }

21   }

再创建Satana.cs:

01 public     class   Satana:BuildCar

02   {

03       public   override   void   BuildEngine()

04       {

05           NewCar.Engine =  "W型12缸发动机" ;

06       }

07  

08       public   override   void   BuildGearing()

09       {

10           NewCar.Gearing = "前置后驱(FR)" ;

11       }

12  

13       public   override   void   BuildBrake()

14       {

15           NewCar.Brake =  "组合式制动系统" ;

16       }

17       public   Satana()

18       {

19           Name =  "SATANA" ;

20       }

21   }

再创建GenerateCar.cs:

01 public   class   GenerateCar

02   {

03      private   BuildCar buildCar;

04      public   BuildCar BuildNewCar

05      {

06          get   {  return   buildCar; }

07          set   { buildCar = value; }

08      }

09      public   string   Generate()

10      {

11          StringBuilder strBuider =  new   StringBuilder();

12          strBuider.AppendFormat( "开始组装{0}轿车. \n" ,buildCar.Name);

13          BuildNewCar.BuildEngine();

14          BuildNewCar.BuildGearing();

15          BuildNewCar.BuildBrake();

16          strBuider.AppendFormat( "{0}轿车组装完毕. \n" ,buildCar.Name);

17          return   strBuider.ToString();

18      }

19      public   GenerateCar(BuildCar newCar)

20      {

21          buildCar = newCar;

22      }

23   }

最后再调用:

01 public   partial   class   Run : Form

02     {

03         public   Run()

04         {

05             InitializeComponent();

06         } 

07       private   void   btnRun_Click( object   sender, EventArgs e)

08         {

09            GenerateCar newCar =  new   GenerateCar( new   Satana());

10             rtbResult.AppendText(newCar.Generate() +  "\n" );

11             rtbResult.AppendText(newCar.BuildNewCar.NewCar.ShowInfo() +  "\n" );

12             newCar =  new   GenerateCar( new   Audi());

13             rtbResult.AppendText(newCar.Generate() +  "\n" );

14             rtbResult.AppendText(newCar.BuildNewCar.NewCar.ShowInfo() +  "\n" );

15         }

16     }

结果如下图:

实现要点

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

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

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

5、对象的构建过程由指导者完成,具体的组成由具体建造者完成,表示与构建分离。

6、 建造者和指导者是建造者模式的关键点,如果进行合并或省略就可能会转变到模版方法模式。

7、如果对象的建造步骤是简单的,并且产品拥有一致的接口可以转而使用工厂模式。

效果

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

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

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

适用性

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

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

4 、从代码角度来说, 如果你希望分离复杂类型构建规则和类型内部组成,或者希望把相同的构建过程用于构建不同类型的时候可以考虑使用建造者模式。

5、从应用角度来说, 如果你希望解耦产品的创建过程和产品的具体配件,或者你希望为所有产品的创建复用一套稳定并且复杂的逻辑的时候可以考虑使用建造者模式。

总结

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

2、返回产品的方法是否必须,是否一定要在抽象建造者中有接口根据实际情况而定。如果它们有统一的接口可以在抽象建造者中体现这个抽象方法,如果没有统一的接口(比如,生产毫无关联的产品)则可以在具体建造者中各自实现这个方法,如果创建的产品是一种产品,那么甚至可以省略返回产品的接口(本文的例子就是这样)。

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于步步为营 .NET 设计模式学习笔记 十、Builder(建造者模式)的详细内容...

  阅读:37次

CopyRight:2016-2025好得很程序员自学网 备案ICP:湘ICP备09009000号-16 http://haodehen.cn
本站资讯不构成任何建议,仅限于个人分享,参考须谨慎!
本网站对有关资料所引致的错误、不确或遗漏,概不负任何法律责任。
本网站刊载的所有内容(包括但不仅限文字、图片、LOGO、音频、视频、软件、程序等)版权归原作者所有。任何单位或个人认为本网站中的内容可能涉嫌侵犯其知识产权或存在不实内容时,请及时通知本站,予以删除。

网站内容来源于网络分享,如有侵权发邮箱到:kenbest@126.com,收到邮件我们会即时下线处理。
网站框架支持:HDHCMS   51LA统计 百度统计
Copyright © 2018-2025 「好得很程序员自学网
[ SiteMap ]