第十九章 建造者(Builder)模式
1. 一个产品常有不同的组成成分作为产品的零件,这些零件有可能是对象,也有可能不是对象,它们通常又叫做产品的内部表象(internal representation)。使用建造者模式可以使客户端不需要知道所生成的产品对象有哪些零件,每个产品的对应零件彼此有何不同,是怎么建造出来的以及怎样组成产品的。
2. 建造者模式的简略类图如下:
3. 有些情况下一个对象会有一些重要的性质(零件),在它们没有恰当的值之前,对象不能作为一个完整的产品使用。而另一些情况下,一个对象的一些性质(零件)必须按照某个顺序赋值才有意义。所以当产品的零件建造涉及到复杂的商业逻辑的情况下,这些零件的建造过程往往被“外部化”到另外一个称做建造者的对象里,建造者对象返还给客户端的是一个全部零件都建造完毕的产品对象。
4. 建造者模式利用一个导演者对象和具体建造者对象一个一个地建造出所有的零件,从而建造出完整的产品对象。建造者模式将产品的结构和产品的零件建造过程对客户端隐藏起来,把对建造过程进行指挥的责任和具体建造零件的责任分割开来,达到责任划分的目的。
5. 建造者模式的类图如下:
a) 抽象建造者(Builder)角色:给出一个抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此接口独立于应用程序的商业逻辑。模式中直接创建产品对象的是具体建造者(Concrete Builder)角色。具体建造者类必须实现这个接口所要求的两种方法:一种是建造方法,比如buildPart1(), buildPart2()等等。另一种是结果返还方法,如retrieveResult()。一般来说,产品所包含的零件数目与建造方法的数目相符。
b) 具体建造者(Concrete Builder)角色:担任这个角色的是应用程序紧密相关的一些类,它们在应用程序调用下创建产品的实例。这个角色要完成的任务包括:实现抽象建造者Builder所声明的接口,给出一步一步地完成创建产品实例的操作以及在建造过程完成后,提*品的实例。
c) 导演者(Director)角色:担任这个角色的类调用具体建造者角色以创建产品对象。导演角色并没有产品类的具体知识,真正拥有产品类的具体知识的是具体建造者角色。导演者只知道产品类各零件的构建顺序。
d) 产品(Product)角色:产品便是建造中的复杂对象。一般来说,一个系统中会有多于一个的产品类,而且这些产品类并不一定有共同的接口,而完全可以是不相关联的。
6. 导演者角色是与客户端打交道的角色。导演者角色将客户端创建产品的请求划分为对各个零件的建造请求,再将这些请求委派给具体建造者角色。具体建造者角色是做具体建造工作的,但是却不为客户端所知。一般来说,每有一个产品类,就有一个相应的具体建造者类。这些产品应当有一样数目的零件,而每有一个零件就相应地在所有的建造者角色里有一个建造方法。
7. 客户端使用建造者模式的顺序图如下:
把创建具体建造者对象的任务交给客户端而不是导演者对象,是为了将导演者对象与具体建造者对象的耦合变成动态的,从而使导演者对象可以操纵数个具体建造者对象中的任何一个。
8. 当系统中有两个以上的具体产品类时,可以为这些具体产品类定义一个共同的接口(可以是空接口,如果产品类间没有共性的话。)。而抽象构造者Builder类的retrieveResult()方法应该返回这个共同的抽象产品接口。如果具体产品类是第三方提供的,不能修改,那只好将retrieveResult()方法从抽象建造者中去掉,而不同产品的具体建造者的retrieveResult()方法返回不同的具体产品类。如果不同产品所具有的零件数不同,那么抽象建造者的零件构造方法的个数应该与具有最多零件的产品的零件数一致,而具有较少零件的产品的具体建造者可以使用空的零件建造方法。
9. 如果设计师非常肯定系统只需要一个具体建造者角色的话,可以省略掉抽象建造者角色和导演者角色:
在这种情况下,就如同模版方法(Template Method)模式,construct()方法就是模版方法。
10. 在以下情况下应当使用建造者模式:
a) 需要生成的产品对象有复杂的内部结构。
b) 需要生成的产品对象的属性相互依赖。建造者模式可以强制实行一种分步骤进行的建造过程。
c) 产品的某些关键属性没有确定之前,产品对象不能使用。这时产品对象的实例化,属性的赋值和使用仍然是分步骤进行的。
d) 在对象创建过程中会使用到系统中的其他一些对象,这些对象在产品对象的创建过程中不易得到。
11. 建造者模式主要有以下效果:
a) 使得产品的内部表象可以独立地变化。客户端不必知道产品内部组成的细节。
b) 每一个Builder都相对独立,而与其他的Builder无关。
c) 模式所建造的最终产品更易于控制。
12. 在抽象工厂模式中,每一次工厂对象被调用时都会返还一个完整的产品对象,而客户端有可能会决定把这些产品组装成一个更大更复杂的产品。建造者则不同,它一点一点地建造出一个复杂的产品,而这个产品的组装过程就发生在建造者角色内部。建造者模式的客户端拿到的是一个完整的最后产品。换言之,抽象工厂模式处在更加具体的尺度上,而建造者模式则处于更加宏观的尺度上。一个系统可以由一个建造者模式和一个抽象工厂模式组成,客户端通过调用这个建造者,间接地调用另一个抽象工厂模式的工厂角色。工厂模式返还不同产品族的零件,而建造者模式则把它们组装起来。