设计模式之建造者模式

94 阅读1分钟

案例:造车,在模板方法模式中使用的案例是造车,继续扩展这个案例来介绍建造者模式。这次要造宝马汽车和奔驰汽车,但是要求:汽车的启动、停止、鸣笛、引擎轰鸣这些方法都由自己控制。

先设计一个不用设计模式实现的方式。

类图:

代码:

import java.util.ArrayList;

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 public void setSequence(ArrayList<String> sequence) {
        this.sequence = sequence;
    }

    // 按照启动顺序执行4个方法
    final public void run() {
        for (int i = 0; i < sequence.size(); i++) {
            String actionName = sequence.get(i);
            if (actionName.equalsIgnoreCase("start")) {
                start();
            } else if (actionName.equalsIgnoreCase("stop")) {
                stop();
            } else if (actionName.equalsIgnoreCase("alarm")) {
                alarm();
            } else if (actionName.equalsIgnoreCase("engineBoom")) {
                engineBoom();
            } else {
                System.out.println("无法识别:" + actionName);
                System.exit(-1);
            }
        }
    }

}

public class Benz extends Car {

    @Override
    protected void start() {
        System.out.println("Benz start...");
    }

    @Override
    protected void stop() {
        System.out.println("Benz stop...");
    }

    @Override
    protected void alarm() {
        System.out.println("Benz alarm...");
    }

    @Override
    protected void engineBoom() {
        System.out.println("Benz engine boom...");
    }
}

public class BMW extends Car {

    @Override
    protected void start() {
        System.out.println("BMW start...");
    }

    @Override
    protected void stop() {
        System.out.println("BMW stop...");
    }

    @Override
    protected void alarm() {
        System.out.println("BMW alarm...");
    }

    @Override
    protected void engineBoom() {
        System.out.println("BMW engine boom...");
    }
}

public class Client {

    public static void main(String[] args) {

        Benz benz = new Benz();
        ArrayList<String> sequence = new ArrayList<>();
        sequence.add("engineBoom");
        sequence.add("start");
        sequence.add("stop");

        benz.setSequence(sequence);
        benz.run();

    }

}

接下来看看使用建造者模式怎么做。

类图:

代码:

import java.util.ArrayList;

public abstract class CarBuilder {

    public abstract void setSequence(ArrayList<String> sequence);
    public abstract Car getCar();

}

public class BenzBuilder extends CarBuilder {

    private Benz benz = new Benz();

    @Override
    public void setSequence(ArrayList<String> sequence) {
        benz.setSequence(sequence);
    }

    @Override
    public Car getCar() {
        return benz;
    }
}


public class BMWBuilder extends CarBuilder {

    private BMW bmw = new BMW();

    @Override
    public void setSequence(ArrayList<String> sequence) {
        bmw.setSequence(sequence);
    }

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

public class Client {

    public static void main(String[] args) {

        ArrayList<String> sequence = new ArrayList<>();
        sequence.add("engineBoom");
        sequence.add("start");
        sequence.add("stop");

        BenzBuilder benzBuilder = new BenzBuilder();
        benzBuilder.setSequence(sequence);
        Benz benz = (Benz) benzBuilder.getCar();
        benz.run();

        BMWBuilder bmwBuilder = new BMWBuilder();
        bmwBuilder.setSequence(sequence);
        BMW bmw = (BMW) bmwBuilder.getCar();
        bmw.run();

    }

}

继续优化设计,设计一个专门的类来设置start()、stop()、alarm()、engineBoom()这4个方法的顺序。

修改类图:

增加了Director类,对Car的4个方法的顺序进行封装:

  • A型号Benz,run()的顺序:start()、stop()
  • B型号Benz,run()的顺序:engineBoom()、start()、stop()
  • A型号BMW,run()的顺序:alarm()、start()、stop()
  • B型号BMW,run()的顺序:start()
  • ......

代码:

import java.util.ArrayList;

public class Director {

    private ArrayList<String> sequence = new ArrayList<>();
    private BenzBuilder benzBuilder = new BenzBuilder();
    private BMWBuilder bmwBuilder = new BMWBuilder();

    public Benz getABenz() {
        sequence.clear();
        sequence.add("start");
        sequence.add("stop");
        benzBuilder.setSequence(sequence);
        return (Benz) benzBuilder.getCar();
    }

    public Benz getBBenz() {
        sequence.clear();
        sequence.add("engineBoom");
        sequence.add("start");
        sequence.add("stop");
        benzBuilder.setSequence(sequence);
        return (Benz) benzBuilder.getCar();
    }

    public BMW getABMW() {
        sequence.clear();
        sequence.add("alarm");
        sequence.add("start");
        sequence.add("stop");
        bmwBuilder.setSequence(sequence);
        return (BMW) bmwBuilder.getCar();
    }

    public BMW getBBMW() {
        sequence.clear();
        sequence.add("start");
        bmwBuilder.setSequence(sequence);
        return (BMW) bmwBuilder.getCar();
    }

}

public class Client {

    public static void main(String[] args) {

        Director director = new Director();

        for (int i = 0; i < 10; i++) {
            director.getABenz().run();
        }

        for (int i = 0; i < 10; i++) {
            director.getBBenz().run();
        }

        for (int i = 0; i < 10; i++) {
            director.getABMW().run();
        }

    }

}

这就是建造者模式,其中涉及到一些角色:

  • Client:客户端,比如项目中的其他模块
  • Car抽象类以及Benz、BMW两个子类:产品类(Product),实现了模板方法模式,其中定义模板方法和基本方法
  • CarBuilder以及BenzBuilder和BMWBuilder两个子类:建造者(Builder)
  • Director:导演类,负责安排已有模块的顺序,依赖Builder进行建造

建造者模式和工厂模式(包括工厂方法模式抽象工厂模式)非常类似,但是侧重点不同:

  • 建造者模式是在基本方法已经实现的基础上,关注基本方法的调用顺序安排
  • 工厂模式注重的是高效创建对象

本文原书:《您的设计模式》 作者:CBF4LIFE