建造者模式

-- 什么是建造者模式?
-- 建造者模式应用场景?
-- 建造者模式和工厂模式的区别?

定义

指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示。

应用场景

建造者(Builder)模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用。

  • 创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。
  • 创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。

实现

展现的是《设计模式之禅》里面的例子。以车模型为例,每种车都可根据几个动作排布。
CarModel.java

public abstract class CarModel {

    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 run() {
        for (int i = 0; i < this.sequence.size(); i++){
            String actionName = this.sequence.get(i);
            if (actionName.equalsIgnoreCase("start")) {
                this.start();
            } else if (actionName.equalsIgnoreCase("stop")) {
                this.stop();
            } else if (actionName.equalsIgnoreCase("alarm")) {
                this.alarm();
            } else if (actionName.equalsIgnoreCase("engine boom")) {
                this.engineBoom();
            }
        }
    }
    final public void setSequence (ArrayList sequence) {
        this.sequence = sequence;
    }
}

BenzModel.java

public class BenzModel extends CarModel {
    @Override
    protected void alarm() {
        System.out.println("奔驰车的喇叭声音是这个样子的...");
    }

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

    @Override
    protected void start() {
        System.out.println("奔驰车跑起来是这个样子的...");
    }

    @Override
    protected void stop() {
        System.out.println("奔驰车应该这样停车...");
    }
}

BMWModel.java

public class BMWModel extends CarModel {
    @Override
    protected void alarm() {
        System.out.println("宝马车的喇叭声音是这个样子的...");
    }

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

    @Override
    protected void start() {
        System.out.println("宝马车跑起来是这个样子的...");
    }

    @Override
    protected void stop() {
        System.out.println("宝马车应该这样停车...");
    }
}

Client.java

public class Client {

    public static void main(String[] args) {
        //传统做法
        BenzModel benz = new BenzModel();
        ArrayList<String> sequence = new ArrayList<>();
        sequence.add("engine boom"); // 客户要求,run的时候先发动引擎
        sequence.add("start"); // 启动起来
        sequence.add("stop"); // 开了一段就停下来
        // 我们把这个顺序赋予奔驰车
        benz.setSequence(sequence);
        benz.run();
    }
}

传统的做法到这里就直接将动作顺序在调用端一一列出来了,但这样的话,如果再来一个别的动作顺序,又得再列一大串代码,直到把你逼疯。其次,如果其他地方也要用到这个车模型,就得再copy一遍。下面加入建造者看下~

CarBuilder.java

public abstract class CarBuilder {

    public abstract void setSequence(ArrayList<String> sequence);
    public abstract CarModel getCarModel();
}

BenzBuilder.java

public class BenzBuilder extends CarBuilder {
    private BenzModel benz = new BenzModel();
    @Override
    public void setSequence(ArrayList<String> sequence) {
        this.benz.setSequence(sequence);
    }

    @Override
    public CarModel getCarModel() {
        return benz;
    }
}

BMWBuilder.java

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

    @Override
    public CarModel getCarModel() {
        return bmw;
    }
}

建造者创建完了,还需要一个指挥官来指挥建造者才行,指挥官想生成3种类型的奔驰。
Director.java

public class Director {
    private ArrayList<String> sequence = new ArrayList<>();
    private BenzBuilder benzBuilder = new BenzBuilder();
    private BMWBuilder bmwBuilder = new BMWBuilder();

    //A类型的奔驰
    public BenzModel getABenzModel() {
        //清理场景,这里是一些初级程序员不注意的地方
        this.sequence.clear();
        this.sequence.add("start");
        this.sequence.add("stop");
        this.benzBuilder.setSequence(sequence);
        return (BenzModel) this.benzBuilder.getCarModel();
    }

    //B类型的奔驰
    public BenzModel getBBenzModel() {
        //清理场景,这里是一些初级程序员不注意的地方
        this.sequence.clear();
        this.sequence.add("engine boom");
        this.sequence.add("start");
        this.sequence.add("stop");
        this.benzBuilder.setSequence(sequence);
        return (BenzModel) this.benzBuilder.getCarModel();
    }

    //C类型的奔驰
    public BenzModel getCBenzModel() {
        //清理场景,这里是一些初级程序员不注意的地方
        this.sequence.clear();
        this.sequence.add("alarm");
        this.sequence.add("start");
        this.sequence.add("stop");
        this.benzBuilder.setSequence(sequence);
        return (BenzModel) this.benzBuilder.getCarModel();
    }

}

Client.java

public class Client {

    public static void main(String[] args) {
        //传统做法
        ...

        //建造者模式
        System.out.println("==========A==========");
        Director director = new Director();
        director.getABenzModel().run();
        System.out.println("==========B==========");
        director.getBBenzModel().run();
        System.out.println("==========C==========");
        director.getCBenzModel().run();

    }
}

最后,在客户想要那种车模型的时候,指挥官就马上去安排了。

建造者模式和工厂模式的区别?

学完这个模式的时候,一开始还是有点蒙圈的,将初始化的零散工作放在一个方法里,在调用的时候直接根据类型去获取,这不是工厂模式吗?但仔细回想上个例子,汽车是一个工厂,然后子部件如空调,发动机作为一个单独的对象,在工厂里面有创建方法,当需要哪个部件的时候,就通过工厂方法去实例化出来。建造者模式是将A,B,C类型的车作为一个整体,通过指挥官去组装。
从这两个例子也就可以看出: 建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程。

《设计模式之禅》 对于这两者的区别是这么理解的:
建造者模式最主要的功能是基本方法的调用顺序安排,也就是这些基本方法已经实现了,通俗地说就是零件的装配,顺序不同产生 的对象也不同;
而工厂方法则重点是创建,创建零件是它的主要职责,组装顺序则不是它关心的。

posted @ 2019-11-29 13:51  cilieyes  阅读(103)  评论(0编辑  收藏  举报