建造者模式定义
意图
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
适用性
在以下情况使用Builder模式
- 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
- 当构造过程必须允许被构造的对象有不同的表示时。
结构
此模式结构如下图所示
Builder
– 为创建一个Product对象的各个部件指定抽象接口。ConcreteBuilder
– 实现Builder的接口以构造和装配该产品的各个部件。
– 定义并明确它所创建的表示。
– 提供一个检索产品的接口。Director
– 构造一个使用Builder接口的对象。Product
– 表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。
– 包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
协作
- 客户创建Director对象,并用它所想要的Builder对象进行配置。
- 一旦产品部件被生成,Director就会通知Builder。
- Builder处理Director的请求,并将部件添加到该产品中。
- 客户从Builder中检索产品。
下面的交互图展示了Builder和Director是如何与一个client协作的
效果
它使你可以改变一个产品的内部表示
Builder对象提供给导向器一个构造产品的抽象接口。该接口使得生成器可以隐藏这个产品的表示和内部结构。它同时也隐藏了该产品是如何装配的。因为产品是通过抽象接口构造的,你在改变该产品的内部表示时所要做的只是定义一个新的生成器。它将构造代码和表示代码分开
Builder模式通过封装一个复杂对象的创建和表示方式提高了对象的模块性。客户不需要知道定义产品内部结构的类的所有信息;这些类是不出现在Builder接口中的。每个ConcreteBuilder包含了创建和装配一个特定产品的所有代码。这些代码只需要写一次;然后不同的Director可以复用它以在相同部件集合的基础上构作不同的Product。它使你可对构造过程进行更精细的控制
Builder模式与一下子就生成产品的创建型模式不同,它是在导向者的控制下一步一步构造产品的。仅当该产品完成时导向者才从生成器中取回它。因此Builder接口相比其他创建型模式能更好的反映产品的构造过程。这使你可以更精细的控制构建过程,从而能更精细的控制所得产品的内部结构。
建造者模式实现(Implement)
在之前读《Effetive Java》时里面有提到“遇到多个构造器参数时考虑用构造器”,之前也总结了一下:链接
该文主要探讨了Builder模式对于构造器参数比较多的时候的意义,但是在对构造过程进行精细的控制时,Builder模式也能发挥自己的作用。
案例
先来看现实的一个场景,日常生活中汽车随处可见,现在汽车厂商Benz和Audi要制造汽车,来看下用Builder模式是怎么实现的。
代码实现
先定义我们的Product,Car的抽象类,汽车包含发动机,车轮,车载系统和品牌四个部分
具体的BenzCar类
接下来,我们定义抽象的CarBuilder类
现在需要一个具体的builder实现类BenzCarBuilder
还有最后一个关键角色Director
装配过程的代码
现在对上面几段代码进行详细的分析,Director在这里充当的是指挥者的角色,Director本身并不参与创建对象,construct()方法都是在指挥builder来装配对象,而我们调用的时候直接使用Director进行创建BenzCar就行了,调用者并不需要知道build的过程细节是什么,这里也体现出builder模式的优点,将产品表示和构造分离了。除此之外,我们可以在Director中的construct()方法按自己的需求对构造过程进行修改,这也体现出builder模式的优点。
实际使用有时候会把Director省略,在builderTest2()和builderTest3()方法中就省略了Director,而且完全可以自定义装配的过程,比如先装配发动机还是先装配车载系统。代码如下
总结
本文对Builder模式进行了介绍,经过分析后发现Builder模式具有以下几个优点:
- 将产品自身与构造过程解耦,客户端并不需要知道产品内部组成的细节
- builder之间没有任何关联,使用不同的builder可以产生不同的产品,而且可以增加新的builder来扩展
- 可以精细地控制产品的整个创建过程
- 链式的方法调用结构清晰,虽然代码量有所增加,但是代码可读性明显改善