造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。建造者模式属于对象创建型模式。根据中文翻译的不同,建造者模式又可以称为生成器模式。
无论是在现实世界中还是在软件系统中,都存在一些复杂的对象,它们拥有多个组成部分,如汽车,它包括车轮、方向盘、发送机等各种部件。而对于大多数用户而言,无须知道这些部件的装配细节,也几乎不会使用单独某个部件,而是使用一辆完整的汽车,可以通过建造者模式对其进行设计与描述,建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节。
在软件开发中,也存在大量类似汽车一样的复杂对象,它们拥有一系列成员属性,这些成员属性中有些是引用类型的成员对象。而且在这些复杂对象中,还可能存在一些限制条件,如某些属性没有赋值则复杂对象不能作为一个完整的产品使用;有些属性的赋值必须按照某个顺序,一个属性没有赋值之前,另一个属性可能无法赋值等。
复杂对象相当于一辆有待建造的汽车,而对象的属性相当于汽车的部件,建造产品的过程就相当于组合部件的过程。由于组合部件的过程很复杂,因此,这些部件的组合过程往往被“外部化”到一个称作建造者的对象里,建造者返还给客户端的是一个已经建造完毕的完整产品对象,而用户无须关心该对象所包含的属性以及它们的组装方式,这就是建造者模式的模式动机。
比较常见的是下面这种只有一个产品的模式结构,大多数的书中也是这样讲的。
从图中我们可以看出,创建者模式由四部分组成。
创建者模式的流程是这样的,客户端需要创建什么对象实例就创建一个导演类和这个对象的创建者,将创建者传给导演类,导演类会使用创建者来创建具体的产品。但是导演类并不清楚产品究竟是怎么创建出来的,产品的实际创建过程是由具体工厂来负责的,具体工厂在创建时也是分为若干步骤,比如图中表示出了两个部分part1和part2,分别对应产品的两个零件,具体工厂就是通过一点一点的创建产品的每个部分最后组成产品。
在实际的应用中不可能只用创建者模式创建一种产品,下边就以两种产品为例讨论一下怎么样通过创建者模式创建多种产品。
要想使用创建者模式创建多种产品的话,有一个隐含的前提,那就是这些产品有共同的特性,也就是说可以用共同的接口实现。比如我们的上图中Product1和Product2都继承自AbstractProduct,并且这两种产品都有part1和part2两部分,但是每种产品的part1和part2实现方式不同,这时就可以使用创建者模式。除了这一点外,另外需要主要的是在AbsractBuilder中返回的是产品的共同父类,这样才能满足多个产品的返回都正常。
可能有人会产生疑问,如果一个产品有3部分组成而另一个产品由2部分组成,是不是就不能使用创建者模式了呢。不是的,同样可以使用创建者模式,在产品类中定义三部分,在只有2不部分的产品中不属于自己的哪一部分设为空就好了。
前边我们讲了土豪坐车的例子,但是还没讲土豪的汽车是怎么生产出来的,我们知道汽车的生产过程是很复杂的,同时汽车又是由很多组建组成的。但是土豪不需要知道汽车是怎样制造出来的,其中的零件怎么安装,按照什么顺序安装等等,这些土豪都不需要知道。所以我们应该将汽车生产这一部分移到一个特定的地方。
可能有人会想我们可以在Audi类的构造方法中进行零件的生产和拼装,但是这样做的话Benz车和Bmw车都需要在构造方法中加入制造零件和拼装组建的功能。一是显得的很麻烦,因为每个类都增加了一块很复杂的代码,同时我们应当认识到,虽然Audi和Bnez的制造细节不同但是大体的流程是差不多的,大家都由引擎,轮胎,方向盘等组成,这些相似的代码在不同的类中重复是很不优雅的。
像这种产品的组成部分相同但是具体生产细节不同的情况特别适合使用创建者模式。
package com.designpattern.builder;
/** * 抽象建造类,提供创建产品的共同接口,不同的产品可以有自己的具体实现 * @author * */
public abstract class AbstractBuilder {
/** * 创建引擎 */
public abstract void buildEngine();
/** * 创建车玻璃 */
public abstract void buildGlass();
/** * 创建方向盘 */
public abstract void buildSteeringWheel();
/** * 返回创建好的产品,为了兼容所有的产品,返回的类型定为共同的父类 * @return */
public abstract Car getCar();
}
package com.designpattern.builder;
/** * Audi的具体创建者 * @author xingjiarong * */
public class AudiBuilder extends AbstractBuilder{
/** * 创建一个各部分都为空的对象 */
Audi audi = new Audi();
/** * 创建各个部分 */
public void buildEngine() {
audi.engine = "AudiEngine";
}
public void buildGlass() {
audi.glass = 3.5;
}
public void buildSteeringWheel() {
audi.steeringWheel = "AudiSteeringWheel";
}
/** * 返回创建好的对象 */
public Car getCar() {
return audi;
}
}
package com.designpattern.builder;
/** * 导演类,根据按照产品的建造和组装顺序组装产品 * @author xingjiarong * */
public class Director {
private AbstractBuilder build;
public Director(AbstractBuilder build){
this.build = build;
}
/*** * 组成产品的方法,组成的过程可能是有顺序的 * @return */
public Car construct(){
build.buildSteeringWheel();
build.buildGlass();
build.buildEngine();
return build.getCar();
}
}
package com.designpattern.builder;
public abstract class Car {
/** * 汽车引擎,实际应用中应该是一个对象,这里用字符串来表示 */
public String engine;
/** * 汽车玻璃,不同的汽车大小不一样,需要根据汽车的型号计算 */
public double glass;
/** * 汽车方向盘 */
public String steeringWheel;
public abstract void drive();
}
package com.designpattern.builder;
public class Main {
public static void main(String[] args) throws Exception {
/** * 创建导演类和Audi的建造者 */
AudiBuilder build = new AudiBuilder();
Director director = new Director(build);
/** * 利用导演类获得汽车而不是自己获得汽车 */
Car car = director.construct();
//开车
car.drive();
}
}
Audi没有变化,Benz车的代码和Audi车的代码是相似的,不再贴具体的代码,最后会附上源码。
在抽象工厂模式中,每一次工厂对象被调用时都会返回一个完整的产品对象,而客户端有可能会决定把这些产品组装成一个更大更复杂的产品,也有可能不会。建造类则不同,它一点一点的建造出一个复杂的产品,而这个产品的组装过程就发生在创建者角色内部。建造者的客户端拿到的是一个完整的最后产品。
换言之,抽象工厂模式处在更加具体的尺度上,而建造者模式处在更加宏观的尺度上。一个系统可以由一个建造模式和一个抽象工厂模式组成,客户端通过调用这个创建角色,间接地调用另一个抽象工厂模式的工厂角色。工厂模式返回不同产品族的零件,而建造者模式则把他们组装起来。
源码下载:http://download.csdn.net/detail/xingjiarong/9299923