建造者模式也叫生成器模式,具有封装性、易扩展等优势,其定义为:将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示。

    假定我们现在接到一个需求,要造出一辆奔驰,那么我们可以做如下设计:

    首先,本着抽象原则,我们肯定是会先定义一个接口Car,里面包含了车子都会有的部件,如下:

public abstract class Car {/** 引擎 */private String engine;/** 车身 */private String bodywork;/** 底盘 */private String chassis;/** 轮胎 */private String tyre;@Overridepublic String toString() {return new ToStringBuilder(this).append("engine", engine).append("bodywork", bodywork).append("chassis", chassis).append("tyre", tyre).toString();}//省略get set方法。。。
}

    接下来,来定义我们的奔驰,此处奔驰与普通车的特殊在于他有一个全景天窗,我们来看Benz:

public class Benz extends Car {public void sunroof () {System.out.println("我有全景天窗!");}
}

    要建造一辆奔驰,那么接下来我们需要一个建造者来完成这件事情,如下先定义出通用建造者的接口:

public interface ICarBuilder {/*** 建造引擎*/void buildEngine();/*** 建造车身*/void buildBodywork();/*** 建造底盘*/void buildChassis();/*** 建造轮胎*/void buildTyre();/*** 建造车子*/Car build();
}

    接下来我们来实现奔驰建造者,用以制造我们的奔驰:

public class BenzBuilder implements ICarBuilder {private static Car benz;public BenzBuilder() {}public void buildEngine() {benz.setEngine("奔驰引擎");}public void buildBodywork() {benz.setBodywork("奔驰车身");}public void buildChassis() {benz.setChassis("奔驰底盘");}public void buildTyre() {benz.setTyre("奔驰轮胎");}public Car build () {benz = new Benz();this.buildEngine();this.buildBodywork();this.buildChassis();this.buildTyre();return benz;}
}

    通过奔驰的建造者,我们只要调用build方法,就可以实现奔驰的建造,这是一种最简易化的建造者模式。我们来看一下建造奔驰:

public static void main(String[] args) {ICarBuilder benzBuilder = new BenzBuilder();Car benz = benzBuilder.build();System.out.println(benz);
}

输出结果:

org.white.common.test.design.model.Benz@3af49f1c[engine=奔驰引擎,bodywork=奔驰车身,chassis=奔驰底盘,tyre=奔驰轮胎]

    可以看到奔驰已经建造成功,那么接下来,加入又需求我们建造一辆沃尔沃,我们怎么办呢?接下来就要用到完整版的建造者模式了,类图如下:

【设计模式】建造者模式详解-编程之家

    这里引入了Director类来作为一个控制器,根据不同的指令来建造不同的车,这里需要对上面BenzBuilder类作如下修改:

    /** 构造方法中新建对象 */public BenzBuilder() {benz = new Benz();}/** build方法不再自行构建,责任交还给Director类,之前是自己充当了Director类的职责 */public Car build () {return benz;}

    接下来来看CarDirector类的代码如下:


public class CarDirector {/***  使用不同的建造器建造不同的车*/public Car construct(ICarBuilder builder) {builder.buildEngine();builder.buildBodywork();builder.buildChassis();builder.buildTyre();return builder.build();}
}

    可以通过代码看出,我们传入奔驰的建造器就可以建造一台奔驰,那么按现在的代码结构这里我们要建造一台沃尔沃,只需要新加一个Volvo类和一个VolvoBuilder类就可以了,不会对原有代码造成影响,后续不论造什么车,都可以直接加上各自的建造器和各自的车实体类就可以完成,不需要修改原有代码实现,这样就会获得一个良好的扩展性。接下来我们来看建造一台沃尔沃所需代码:

    首先是Volo类:

public class Volvo extends Car {public void safe () {System.out.println("我有自动驾驶系统,我很安全!");}
}

    接下来是VolvoBuilder类:

public class VolvoBuilder implements ICarBuilder {private static Car volvo;public VolvoBuilder() {volvo = new Volvo();}public void buildEngine() {volvo.setEngine("沃尔沃引擎");}public void buildBodywork() {volvo.setBodywork("沃尔沃车身");}public void buildChassis() {volvo.setChassis("沃尔沃底盘");}public void buildTyre() {volvo.setTyre("沃尔沃轮胎");}public Car build() {return volvo;}
}

    接下来写测试代码测试是否建造成功:

public static void main(String[] args) {CarDirector director = new CarDirector();Car benz = director.construct(new BenzBuilder());Car volvo = director.construct(new VolvoBuilder());System.out.println(benz.toString());System.out.println(volvo.toString());
}

    运行结果如下

org.white.common.test.design.model.Benz@3af49f1c[engine=奔驰引擎,bodywork=奔驰车身,chassis=奔驰底盘,tyre=奔驰轮胎]
org.white.common.test.design.model.Volvo@19469ea2[engine=沃尔沃引擎,bodywork=沃尔沃车身,chassis=沃尔沃底盘,tyre=沃尔沃轮胎]

    可以看到奔驰和沃尔沃都建造成功了。

下面来总结建造者模式的优点:

  1. 强封装性:作为client,我们并不需要知道建造一辆车的过程,一切建造过程都封装在各自的建造器(Builder)中,我们只需发出建造奔驰的指令,则可以通知BenzBuilder建造一台奔驰,并不知道他到底是怎么制造的。
  2. 强扩展性:通过上面的代码可以看出,我们需要建造其他车,是很容易扩展的,而且不会对原有代码造成任何影响,这一点是很重要的。
  3. 强差异化:各自的建造过程由各自负责,所以可以实现各自的细节化

欢迎关注个人博客:blog.scarlettbai.com