jdk中的设计模式之生成器模式(Builder)

来源:互联网 发布:c语言表示最大公约数 编辑:程序博客网 时间:2024/06/05 03:44

一、生成器模式简介:

        生成器模式的意图是将一个复杂对象的构建与它的表示分离,使得同样的构造过程可以创建不同的表示。

        那么我们为什么需要生成器模式呢?

      理由如下:在软件设计中,有时候面临着一个非常复杂的对象的创建工作。这个复杂的对象通常可以分成几个较小的部分,由各个子对象组合出这个复杂对象的过程相对来说比较稳定,但是子对象的创建过程各不相同并且可能面临变化。根据OOD中的OCP原则,应该对这些子对象的创建过程进行变化封装。

       生成器模式的思路是:定义一个抽象的建造者的角色(Builder),规定所有具体的建造者都应该具有的功能——这些功能就是如何创建复杂对象的某个特定部分(子对象),而具体如何创建子对象有具体的创建者实现。再定义一个指导者的角色,它把创建者作为工具,知道如何使用这个工具来创建复杂对象。这样,客户在需要创建这个复杂对象的时候,只需要给指导者一个具体的创建者就可以了。至于具体创建者如何创建子对象的细节以及这些子对象之间的差异,不是指导者,也不是客户关心的。

       生成器模式适用于:1、当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方法时;2、当构造过程必须允许被构造的对象有不同的表示时。

        生成器模式的类图如下:



       使用生成器模式时的顺序图如下:



二、jdk中的生成器模式

      在jdk中应用了Builder模式的类是StringBuilder类(嘿嘿,它们两的名字是不是有点像大笑)。StringBuilder类是jdk5.0引入的一个新类,它提供了一个与StringBuffer兼容的API,但不保证同步,该类被设计用作StringBuffer类的一个简易替换。

    StringBuilder类重载的append方法使用了生成器模式,该方法几乎接收任何对象来构造一个字符串对象,使得用户只需使用同样的方法而不需要知道传入的对象是如何被表示的即可构造一个字符串,真正达到了生成器模式的意图:将一个复杂对象的构建与它的表示分离,使得同样的构造过程可以创建不同的表示。

     那么StringBuilder类的生成器模式的效果如何呢?由于StringBuilder类的append方法使用了生成器模式,所以当我们想要创建一个复杂的StringBuilder对象时,不再需要在一开始就创建出该对象,可以通过不断使用append方法的途径,最终构造出StringBuilder对象,就像上面的顺序图一样通过BuildPartA()、BuilldPartB()、
BuildPartC()的方法得到各个部件,最终通过组合得到我们想要的复杂对象。

     那么在StringBuilder类中实现生成器模式的可行性如何呢?虽然构建复杂StringBuilder的几个部件千变万化——所以要封装成方法,而且还用到了重载,但是由这几个部件组合出复杂对象的过程相对来说比较稳定,所以使用生成器模式是完全可行。

三、关于生成器模式的思考

      写到这里,对着书本和jdk源码,发现这个Builder模式的变化真的好大啊,可见实践和理论的差距真的好大,但是,不可否认的是:理论其实也很重要!在这里我想补充一下一个用到了生成器模式的yy场景
(转自:http://www.cnblogs.com/1984Bingo/archive/2011/03/22/1990943.html):

    假设烤牛肉的制作包括:放盐(估计会放一点吧)、烧烤 两个步骤。如果你是顾客,你只想要烤牛肉这个产品,并且你想要5成熟的或者是7成熟的,至于怎么搞出来的你可能不关心。那这跟生成器设计模式有什么关系呢?仔细想一下你会发现:烤牛肉的过程是稳定的,你想要时,厨师按照流程给你建造一个就行了,如果你想将一个复杂的对象的构建与表示分离,使得同样的构建(放盐、烧烤)得到不同的表示(5成熟的牛肉、7成熟的牛肉)时,你就需要用到一种设计模式:生成器模式。

abstract class BeefBuilder
{
  public abstract void 放盐();
  public abstract void 烧烤();
}

5成熟BeefBuilder : BeefBuilder
{
  public 5成熟BeefBuilder()
     {  
     }
  public override void 放盐()
  {
    放一点盐;
     }
  public override void 烧烤()
  {
        烤5成熟;
      }
}

    当然,7成熟的牛肉按照同样的方式去实现BeefBuilder就行了。

    在客户端还要知道客户到底是想要5成熟的还是要7成熟的牛肉啊!所以还得有一个指挥类(Director),它用来控制牛肉的制作,也用它来隔离用户与制作的隔离。

class BeefDirector
{
  private BeefBuilder BB;
     public BeefDirector(BeefBuilder BB)//告诉指挥者(厨师)你想要几成熟的牛肉
     {
        this.BB=BB;
     }
  public void CreateBeef()//根据客户告诉你的创建烤牛肉
  {
    BB.放盐();
    BB.烧烤();
      }
}

    客户端代码就很简单了:
5成熟BeefBuilder 5成熟=new 5成熟BeefBuilder();
BeefDirector BD=new BeefDirector(5成熟);
BD.CreateBeef();

    总结:
BeefBuilder是指创建对象的各个部件指定的抽象接口,5成熟BeefBuilder是具体的创建者。BeefDirector是指挥者,即是构建一个使用BeefBuilder的接口的对象。