title: 建造者模式
author: rack-leen
avatar: /images/favicon.png
authorDesc: 脱发典范
comments: true
copyright: true
date: 2019-5-19 00:00:00
tags:


建造者模式

定义

Separate the construction of a complex object from its representation so that the same construction process can create different representations.
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

建造者模式示意图

建造者模式

流程

  1. 客户想要对象实例,需要知会指挥者,给指挥者提需求。
  2. 指挥者获取到客户需求(需要创建对象实例),将需求解构,分配给相应的建造者进行建造。
  3. 建造者之间相互独立,建造各自的需求,最终组装成具体的产品。
  4. 产品就是最终的对象实例,返回给客户。

需求

现在客户需要订购东风,奔驰,宝马三种汽车各100辆。四种车的生产顺序是一样的。
客户的需求给指挥者,指挥者将这四种车分别分配给四个建造者建造。

代码实现

  1. 先通过模板方法模式创建出三种汽车实例,这里先创建汽车模板
/**
 * 建造者模式的这个抽象类有模板方法模式的影子
 */
public abstract class Car {
    private ArrayList<String> sequence = new ArrayList<>();
    protected abstract void start();
    protected abstract void stop();
    protected abstract void alarm();
    protected abstract void engineBoom();

    /**
     * 加了final关键字表示run方法和setSequense方法都不能被继承或重写
     *
     * run方法就是模板方法模式中的功能一样,这个更灵活,能自定义执行顺序
     */
    final public void run(){
        for (int i=0 ; i<sequence.size() ; i++){
            String name = this.sequence.get(i);
            if ("start".equals(name)){
                this.start();
            }else if ("stop".equalsIgnoreCase(name)){
                this.stop();
            }else if ("alarm".equalsIgnoreCase(name)){
                this.alarm();
            }else if ("engineBoom".equalsIgnoreCase(name)){
                this.engineBoom();
            }
        }
    }

    /**
     * 从外界传进入执行顺序
     * @param sequence
     */
    final public void setSequence(ArrayList<String> sequence){
        this.sequence = sequence ;
    }
}
  1. 然后通过汽车模板创建出三个以这个模板构建的功能相同的不同种类的汽车类
    奔驰汽车
public class Benz extends Car {
    @Override
    protected void start() {
        System.out.println("奔驰是这样启动的");
    }

    @Override
    protected void stop() {
        System.out.println("奔驰是这样停下来的");
    }

    @Override
    protected void alarm() {
        System.out.println("奔驰的喇叭声音是这样的");
    }

    @Override
    protected void engineBoom() {
        System.out.println("奔驰的引擎声音是这样的");
    }
}

宝马汽车

public class BMW extends Car {
    @Override
    protected void start() {
        System.out.println("宝马是这样启动的");
    }

    @Override
    protected void stop() {
        System.out.println("宝马是这样停下来的");
    }

    @Override
    protected void alarm() {
        System.out.println("宝马的喇叭声音是这样的");
    }

    @Override
    protected void engineBoom() {
        System.out.println("宝马的引擎声音是这样的");
    }
}

东风汽车

public class Dongfeng extends Car{
    @Override
    protected void start() {
        System.out.println("东风是这样启动的");
    }

    @Override
    protected void stop() {
        System.out.println("东风是这样停下来的");
    }

    @Override
    protected void alarm() {
        System.out.println("东风的喇叭声音是这样的");
    }

    @Override
    protected void engineBoom() {
        System.out.println("东风的引擎声音是这样的");
    }
}
  1. 根据不同的汽车类,为它们分配不同的建造者
    奔驰汽车的建造者
public class BenzBuilder extends CarBuilder {
    /* 这里先创建一个产品 */
    private Benz benz = new Benz();

    /*然后为产品设置制造顺序*/
    @Override
    public void setSequense(ArrayList<String> sequense) {
        this.benz.setSequence(sequense);
    }

    /* 产品创建完成就返回这个产品 */
    @Override
    public Car getCar() {
        return this.benz;
    }
}

宝马汽车的建造者

public class BMWBuilder extends CarBuilder {
    private BMW bmw = new BMW();
    @Override
    public void setSequense(ArrayList<String> sequense) {
        this.bmw.setSequence(sequense);
    }

    @Override
    public Car getCar() {
        return this.bmw;
    }
}

东风汽车的建造者

public class DongFengBuilder extends CarBuilder {
    private Dongfeng dongfeng = new Dongfeng();
    @Override
    public void setSequense(ArrayList<String> sequense) {
        this.dongfeng.setSequence(sequense);
    }

    @Override
    public Car getCar() {
        return this.dongfeng;
    }
}
  1. 建造者要建造汽车,需要有总指挥分配需求,进行调度,这里需要有一个总指挥
/**
 * 这是所有建造者的指挥者,它来只会建造者建造产品
 */
public class Director {
    private ArrayList<String> sequense = new ArrayList<>();
    private BenzBuilder benzBuilder = new BenzBuilder();
    private BMWBuilder bmwBuilder = new BMWBuilder();
    private DongFengBuilder dongFengBuilder = new DongFengBuilder();

    /**
     * 宝马模型
     */
    public BMW getBMW(){
        this.sequense.clear();
        this.sequense.add("start");
        this.sequense.add("stop");

        this.bmwBuilder.setSequense(this.sequense);
        return (BMW) this.bmwBuilder.getCar();
    }
    /**
     * 奔驰模型
     */
    public Benz getBenz(){
        this.sequense.clear();
        this.sequense.add("start");
        this.sequense.add("alarm");
        this.sequense.add("stop");

        this.benzBuilder.setSequense(this.sequense);
        return (Benz) this.benzBuilder.getCar();
    }
    /**
     * 东风模型
     */
    public Dongfeng getDongFeng(){
        this.sequense.clear();
        this.sequense.add("start");
        this.sequense.add("engineBoom");
        this.sequense.add("stop");

        this.dongFengBuilder.setSequense(this.sequense);
        return (Dongfeng) this.dongFengBuilder.getCar();
    }

}
  1. 最后,任务分配成功,开始为我们的客户建造需要的产品,场景实现
public class Test {

    public static void main(String[] args) {
        Director director = new Director();
        /**
         * 我们这里是通过指挥者操作建造者建造的产品实例
         */
        /* 奔驰建造 */
        for (int i=0 ; i<100 ; i++){
            director.getBenz().run();
        }
        /* 宝马建造 */
        for (int i=0 ; i<100 ; i++){
            director.getBMW().run();
        }
        /* 东风建造 */
        for (int i=0 ; i<100 ; i++){
            director.getDongFeng().run();
        }
    }

}

应用场景

  1. 相同的功能,不同的执行顺序,产生不同结果。
  2. 多个部件或零件,可以装配到一个对象,但产生结果又不相同。
  3. 产品类非常复杂,调用其顺序不同会产生不同结果。
  4. 在创建对象时会使用系统的其他对象,这些对象在产品创建过程中不易得到。

建造者模式的优点和注意事项

优点

  1. 建造者模式可以使客户不需要知道生产产品的细节,只需要将需求给指挥者就行了,指挥者会让建造者根据产品模型进行建造。这就使得封装性很好。
  2. 一个建造者对应一个产品类型,建造者之间是互相独立的,如果需要新增一个产品类型,只需要新增一个建造者就能扩展。这使得其扩展性很好。
  3. 由于产品对象实例是由建造者建造,我们可以对建造过程进行细化,而不对其他模块产生影响。

注意事项

  1. 建造者注重工艺顺序,与工厂模式的注重点不同。