设计模式-建造者模式

  1. 特定场景:没有人买车会只买一个轮胎或者方向盘,大家买的都是一辆包含轮胎、方向盘和发动机等多个部件的完整汽车。
  2. Builder模式,取名不完整,该模式中包含Builder角色和Director角色
  3. Builder角色是多技能工人,负责干活,具备生产轮胎、方向盘、发动机等
  4. Director角色是管理者,负责调度工人,按照特定的顺序完成生产。
  5. Director返回的是单个产品,单个复杂产品
  6. Builder模式中,Director角色决定了Builder角色的调用顺序
  7. Template方法模式中,负责决定了子类方法的调用顺序
  8. 如何将这些部件组装成一辆完整的汽车并返回给用户,这是建造者模式需要解决的问题。
  9. 建造者模式又称为生成器模式,它是一种较为复杂、使用频率也相对较低的创建型模式。建造者模式为客户端返回的不是一个简单的产品,而是一个由多个部件组成的复杂产品。
  10. 主要优点:
    1.   (1) 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。

      (2) 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。由于指挥者类针对抽象建造者编程,增加新的具体建造者无须修改原有类库的代码,系统扩展方便,符合“开闭原则”

      (3) 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。

  11. 主要缺点:
    1.   (1) 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,例如很多组成部分都不相同,不适合使用建造者模式,因此其使用范围受到一定的限制。

      (2) 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加系统的理解难度和运行成本。

  12. 适用场景:
    1.   (1) 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性。

      (2) 需要生成的产品对象的属性相互依赖,需要指定其生成顺序。

      (3) 对象的创建过程独立于创建该对象的类。在建造者模式中通过引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类和客户类中。

      (4) 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品

  13.   建造者模式定义:
    1.   建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。
    2. 建造者模式是较为复杂的创建型模式,它将客户端与包含多个组成部分(或部件)的复杂对象的创建过程分离,客户端无须知道复杂对象的内部组成部分与装配方式,只需要知道所需建造者的类型即可。它关注如何一步一步创建一个的复杂对象,不同的具体建造者定义了不同的创建过程,且具体建造者相互独立,增加新的建造者非常方便,无须修改已有代码,系统具有较好的扩展性。
  14. 类图
    1.   
    2.  Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口。

      ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。

      Product(产品角色):它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。

       Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。

    3. ConcreteBuilder中实现了buildPartX()方法,通过调用Product的setPartX()方法可以给产品对象的成员属性设值。不同的具体建造者在实现buildPartX()方法时将有所区别,如setPartX()方法的参数可能不一样
    4. 在建造者模式的结构中还引入了一个指挥者类Director,该类主要有两个作用:一方面它隔离了客户与创建过程;另一方面它控制产品的创建过程,包括某个buildPartX()方法是否被调用以及多个buildPartX()方法调用的先后次序等。指挥者针对抽象建造者编程,客户端只需要知道具体建造者的类型,即可通过指挥者类调用建造者的相关方法,返回一个完整的产品对象。在实际生活中也存在类似指挥者一样的角色,如一个客户去购买电脑,电脑销售人员相当于指挥者,只要客户确定电脑的类型,电脑销售人员可以通知电脑组装人员给客户组装一台电脑。
  15. 案例
    1.   游戏中魔鬼、天使、英雄的构造
  16.  对于客户端而言,只需关心具体的建造者即可,一般情况下,客户端类代码片段如下所示: 
    1.  
      Builder  builder = new ConcreteBuilder(); //可通过配置文件实现
      Director director = new  Director(builder);
      Product product = director.construct();

       

  17. 建造者模式与抽象工厂模式有点相似,但是建造者模式返回一个完整的复杂产品,而抽象工厂模式返回一系列相关的产品;在抽象工厂模式中,客户端通过选择具体工厂来生成所需对象,而在建造者模式中,客户端通过指定具体建造者类型并指导Director类如何去生成对象,侧重于一步步构造一个复杂对象,然后将结果返回。如果将抽象工厂模式看成一个汽车配件生产厂,生成不同类型的汽车配件,那么建造者模式就是一个汽车组装厂,通过对配件进行组装返回一辆完整的汽车。
  18. 关于Director的进一步讨论
    1.   指挥者类Director在建造者模式中扮演非常重要的作用,简单的Director类用于指导具体建造者如何构建产品,它按一定次序调用Builder的buildPartX()方法,控制调用的先后次序,并向客户端返回一个完整的产品对象。下面我们讨论几种Director的高级应用方式:
      1. 省略Director: 在有些情况下,为了简化系统结构,可以将Director和抽象建造者Builder进行合并,在Builder中提供逐步构建复杂产品对象的construct()方法。
        1.  
          abstract class ActorBuilder
          {
                 protected  Actor actor = new Actor();
                
                 public  abstract void buildType();
                 public  abstract void buildSex();
                 public  abstract void buildFace();
                 public  abstract void buildCostume();
                 public  abstract void buildHairstyle();
           
                 public Actor construct()
                 {
                        this.buildType();
                        this.buildSex();
                        this.buildFace();
                        this.buildCostume();
                        this.buildHairstyle();
                        return actor;
                 }
          }

           

      2.   钩子方法的引入:建造者模式除了逐步构建一个复杂产品对象外,还可以通过Director类来更加精细地控制产品的创建过程,例如增加一类称之为钩子方法(HookMethod)的特殊方法来控制是否对某个buildPartX()的调用。

               钩子方法的返回类型通常为boolean类型,方法名一般为isXXX(),钩子方法定义在抽象建造者类中。例如我们可以在游戏角色的抽象建造者类ActorBuilder中定义一个方法isBareheaded(),用于判断某个角色是否为“光头(Bareheaded)”,在ActorBuilder为之提供一个默认实现,其返回值为false,代码如下所示:

        1.   
          class ActorController
          {
                 public  Actor construct(ActorBuilder ab)
                 {
                        Actor  actor;
                        ab.buildType();
                        ab.buildSex();
                        ab.buildFace();
                        ab.buildCostume();
                   //通过钩子方法来控制产品的构建
                        if(!ab.isBareheaded())
                        {
                               ab. buildHairstyle();
                        }
                        actor=ab.createActor();
                        return  actor;
                 }
          }

           

  19. 参考:https://blog.csdn.net/csdn_ds/article/details/78468353

posted on 2018-08-11 23:15  手握太阳  阅读(132)  评论(0编辑  收藏  举报

导航