zoukankan      html  css  js  c++  java
  • 设计模式:建造模式

    建造模式  


    一、引子 
        前几天陪朋友去装机店攒了一台电脑,看着装机工在那里熟练的装配着机器,不禁想起 
    来了培训时讲到的建造模式。作为装机工,他们不用管你用的CPU 是Intel 还是AMD,也 
    不管你的显卡是2000 千大元还是白送的,都能三下五除二的装配在一起——一台PC 就诞 
    生了!当然对于客户来说,你也不知道太多关于PC 组装的细节。这和建造模式是多么的相 
    像啊! 
        今天就来探讨一下建造模式 


    二、定义与结构 
        GOF  给建造模式的定义为:将一个复杂对象的构建与它的表示分离,使得同样的构建 
    过程可以创建不同的表示。这句话说得很抽象,不好理解,其实它的意思可以理解为:将构 
    造复杂对象的过程和组成对象的部件解耦。就像攒电脑一样,不管什么品牌的配件,只要兼 
    容就可以装上;同样,一样的配件,可以有好多组装的方式。这是对降低耦合、提高可复用 
    性精神的一种贯彻。 
        当要生成的产品有复杂的内部结构——比如由多个对象组成;而系统中对此产品的需求 
    将来可能要改变产品对象的内部结构的构成,比如说产品的一些属性现在由一个小对象组 
    成,而更改后的型号可能需要N 个小对象组成;而且不能将产品的内部构造完全暴露给客 
    户程序,一是为了可用性,二是为了安全等因素。满足上面的设计环境就可以考虑使用建造 
    模式来搭建框架了。 
        来看看建造模式的组成吧。 
    1)  抽象建造者角色:这个角色用来规范产品对象的各个组成成分的建造。一般而言,此角 
        色独立于应用程序的业务逻辑。 
    2)  具体建造者角色:担任这个角色的是于应用程序紧密相关的类,它们在指导者的调用下 
        创建产品实例。这个角色在实现抽象建造者角色提供的方法的前提下,达到完成产品组 
        装,提供成品的功能。 
    3)  指导者角色:调用具体建造者角色以创建产品对象。指导者并没有产品类的具体知识, 
        真正拥有产品类的具体知识的是具体建造者对象。 
    4)  产品角色:建造中的复杂对象。它要包含那些定义组件的类,包括将这些组件装配成产 
        品的接口。 
        来看下这些角色组成的类图: 


                                              Builder 
            Director 
                            builder 


                                           buildPart1() 
           Director() 
                                           buildPartn() 
           construct() 
                                           retrieveResult() 


                                         ConcreteBuilder 


                                                                            Product 
                                         buildPart1()             create 
                                         buildPartn() 
                                         retrieveResult() 


         首先客户程序创建一个指导者对象,一个建造者角色,并将建造者角色传入指导者对象 
    进行配置。然后,指导者按照步骤调用建造者的方法创建产品。最后客户程序从建造者或者 
    指导者那里得到产品。 
         从建造模式的工作流程来看,建造模式将产品的组装“外部化”到了建造者角色中来。这 
    是和任何正规的工厂模式不一样的——产品的创建是在产品类中完成的。 


    三、实现 
         没有找到好的例子,觉得《java 与模式》中发邮件的例子有点牵强。于是我将Bruce Eckel 
    在《Think in Patterns with Java》中用的例子放到这里权且充个门面。我们知道媒体可以存 
    在不同的表达形式,比如书籍、杂志和网络。这个例子表示不同形式的媒体构造的步骤是相 
    似的,所以可以被提取到指导者角色中去。 


         import java.util.*; 
         import junit.framework.*; 


         //不同的媒体形式: 


         class Media extends ArrayList {} 
         class Book extends Media {} 
         class Magazine extends Media {} 
         class WebSite extends Media {} 


         //  进而包含不同的媒体组成元素: 


         class MediaItem { 
             private String s; 
             public MediaItem(String s) { this.s = s; } 
             public String toString() { return s; } 
         } 
         class Chapter extends MediaItem { 
             public Chapter(String s) { super(s); } 
         } 
         class Article extends MediaItem { 
             public Article(String s) { super(s); } 



    class WebItem extends MediaItem { 
          public WebItem(String s) { super(s); } 



    //  抽象建造者角色,它规范了所有媒体建造的步骤: 


    class MediaBuilder { 
          public void buildBase() {} 
          public void addMediaItem(MediaItem item) {} 
          public Media getFinishedMedia() { return null; } 

    //具体建造者角色 


    class BookBuilder extends MediaBuilder { 
          private Book b; 
          public void buildBase() { 
                System.out.println("Building book framework"); 
                b = new Book(); 
          } 
          public void addMediaItem(MediaItem chapter) { 
                System.out.println("Adding chapter " + chapter); 
                b.add(chapter); 
          } 
          public Media getFinishedMedia() { return b; } 



    class MagazineBuilder extends MediaBuilder { 
          private Magazine m; 
          public void buildBase() { 
                System.out.println("Building magazine framework"); 
                m = new Magazine(); 
          } 
          public void addMediaItem(MediaItem article) { 
                System.out.println("Adding article " + article); 
                m.add(article); 
          } 
          public Media getFinishedMedia() { return m; } 



    class WebSiteBuilder extends MediaBuilder { 
          private WebSite w; 
          public void buildBase() { 
                System.out.println("Building web site framework"); 
                w = new WebSite(); 
          } 



         public void addMediaItem(MediaItem webItem) { 
              System.out.println("Adding web item " + webItem); 
              w.add(webItem); 
         } 
         public Media getFinishedMedia() { return w; } 

    //指导者角色,也叫上下文 


    class MediaDirector { 
         private MediaBuilder mb; 
         public MediaDirector(MediaBuilder mb) { 
              this.mb = mb; //具有策略模式相似特征的 


         } 
         public Media produceMedia(List input) { 
              mb.buildBase(); 
              for(Iterator it = input.iterator(); it.hasNext();) 
                   mb.addMediaItem((MediaItem)it.next()); 
              return mb.getFinishedMedia(); 
         } 



    //测试程序——客户程序角色 


    public class BuildMedia extends TestCase { 
         private List input = Arrays.asList(new MediaItem[] { 
              new MediaItem("item1"), new MediaItem("item2"), 
              new MediaItem("item3"), new MediaItem("item4"), 
         }); 
         public void testBook() { 
              MediaDirector buildBook = new MediaDirector(new BookBuilder()); 
              Media book = buildBook.produceMedia(input); 
              String result = "book: " + book; 
              System.out.println(result); 
              assertEquals(result, "book: [item1, item2, item3, item4]"); 
         } 
         public void testMagazine() { 
              MediaDirector buildMagazine = new MediaDirector(new MagazineBuilder()); 
              Media magazine = buildMagazine.produceMedia(input); 
              String result = "magazine: " + magazine; 
              System.out.println(result); 
              assertEquals(result, "magazine: [item1, item2, item3, item4]"); 
         } 
         public void testWebSite() { 
              MediaDirector buildWebSite = new MediaDirector(new WebSiteBuilder()); 
              Media webSite = buildWebSite.produceMedia(input); 
              String result = "web site: " + webSite; 


                System.out.println(result); 
                assertEquals(result, "web site: [item1, item2, item3, item4]"); 
            } 
            public static void main(String[] args) { 
                junit.textui.TestRunner.run(BuildMedia.class); 
            } 
        } 


    四、应用优点 
        建造模式可以使得产品内部的表象独立变化。在原来的工厂方法模式中,产品内部的表 
    象是由产品自身来决定的;而在建造模式中则是“外部化”为由建造者来负责。这样定义一个 
    新的具体建造者角色就可以改变产品的内部表象,符合“开闭原则”。 
        建造模式使得客户不需要知道太多产品内部的细节。它将复杂对象的组建和表示方式封 
    装在一个具体的建造角色中,而且由指导者来协调建造者角色来得到具体的产品实例。 
        每一个具体建造者角色是毫无关系的。 
        建造模式可以对复杂产品的创建进行更加精细的控制。产品的组成是由指导者角色调用 
    具体建造者角色来逐步完成的,所以比起其它创建型模式能更好的反映产品的构造过程。 


    五、扩展 
        建造模式中很可能要用到组成成品的各种组件类,对于这些类的创建可以考虑使用工厂 
    方法或者原型模式来实现,在必要的时候也可以加上单例模式来控制类实例的产生。但是要 
    坚持一个大前提就是要使引入的模式给你的系统带来好处,而不是臃肿的结构。 
        建造模式在得到复杂产品的时候可能要引用多个不同的组件,在这一点上来看,建造模 
    式和抽象工厂模式是相似的。可以从以下两点来区分两者:创建模式着重于逐步将组件装配 
    成一个成品并向外提供成品,而抽象工厂模式着重于得到产品族中相关的多个产品对象;抽 
    象工厂模式的应用是受限于产品族的(具体参见《深入浅出工厂模式》),建造模式则不会。 
        由于建造模式和抽象工厂模式在实现功能上相似,所以两者使用的环境都比较复杂并且 
    需要更多的灵活性。 
        组合模式中的树枝构件角色(Composite)往往是由多个树叶构件角色(Leaf)组成, 

    因此树枝构件角色的产生可以由建造模式来担当。 

    下载:

    http://download.csdn.net/detail/undoner/5335717

    深入浅出设计模式-中文版

  • 相关阅读:
    Codeforces 798C
    Codeforces 777E
    Codeforces 801C Voltage Keepsake(二分枚举+浮点(模板))
    【NOIP 2017】宝藏
    利普希茨
    【NOIP2008】双栈排序
    捕老鼠
    失格
    【JZOJ4307】喝喝喝
    Blocks
  • 原文地址:https://www.cnblogs.com/wuyida/p/6301025.html
Copyright © 2011-2022 走看看