Java设计模式之建造者模式

2018-09-25  本文已影响0人  CoderJed

因为我们公司制造的悍马汽车得到了客户的满意(Java设计模式之模板方法模式),所以宝马和奔驰也纷纷要和我们公司合作,但是客户提出了新的需求:汽车的启动、停止、喇叭声音、引擎声音都由客户自己控制,他想什么顺序就什么顺序,先看一下基本的类图:

代码如下:

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 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("engine boom")) {
                engineBoom();
            } else {
                System.err.println("无法识别:" + actionName);
                System.exit(-1);
            }
        }
    }
    
    // 允许用户自己设置设置一个启动顺序
    final public void setSequence(ArrayList<String> sequence) {
        this.sequence = sequence;
    }
    
}
public class Benz extends Car {

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

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

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

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

}
public class BMW extends Car {

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

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

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

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

}

某客户要求,我先要1个奔驰车,要求跑的时候,先发动引擎,然后再挂档启动,然后停下来,不需要喇叭,代码这样实现:

public class Client {
    
    public static void main(String[] args) {
        
        Benz benz = new Benz();
        ArrayList<String> sequence = new ArrayList<>();
        sequence.add("engine boom");
        sequence.add("start");
        sequence.add("stop");
        
        benz.setSequence(sequence);
        benz.run();
        
    }

}

运行结果:
Benz's engineBoom()...
Benz's start()...
Benz's stop()...

上面的方式可以实现自定义启动顺序的功能,但还不是建造者模式的风格,建造者模式的类图如下:

代码如下:

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("engine boom");
        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(); 
    }

}

运行结果:
Benz's engineBoom()...
Benz's start()...
Benz's stop()...
BMW's engineBoom()...
BMW's start()...
BMW's stop()...

这四个过程(start,stop,alarm,engineBoom)按照排列组合有很多种,那我们怎么满足这种需求呢?也就是要有个类来安排这几个方法组合,就像导演安排演员一样,那个先出场那个后出场,那个不出场,我们这个也叫导演类,那我们修改一下类图:

增加了Director类,这个类是做了层封装,类中的方法说明如下:

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("engine boom");
        sequence.add("start"); 
        sequence.add("stop"); 
        benzBuilder.setSequence(sequence); 
        return (Benz) benzBuilder.getCar();
    }
    
    public BMW getCBMW() {
        sequence.clear(); 
        sequence.add("alarm"); 
        sequence.add("start"); 
        sequence.add("stop"); 
        bmwBuilder.setSequence(sequence); 
        return (BMW) bmwBuilder.getCar();
    }
    
    public BMW getDBMW() {
        sequence.clear(); 
        sequence.add("start"); 
        bmwBuilder.setSequence(sequence); 
        return (BMW) bmwBuilder.getCar();
    }
    
    /*
     * 这里还可以有很多方法,你可以先停止,然后再启动,或者一直停着不动,等等
     * 导演类嘛,按照什么顺序是导演说了算
     */

}

然后Client就只与Director打交道了,客户说要A类型的奔驰车一万辆,B类型的奔驰车100万辆,C类型的宝马车1000万辆,D类型的不要:

public class Client {

    public static void main(String[] args) {

        Director director = new Director();

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

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

        for (int i = 0; i < 10000000; i++) {
            director.getCBMW().run();
        }
    }

}

这就是建造者模式,中间有几个角色需要说明一下:

大家看到这里估计就开始犯嘀咕了,这个建造者模式和工厂模式非常相似,是的,是非常相似,但是记住一点你就可以游刃有余的使用了:
建造者模式最主要功能是基本方法的调用顺序安排,也就是这些基本方法已经实现了;而工厂方法则重点是创建,你要什么对象我创造一个对象出来,组装顺序则不是他关心的。

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

上一篇 下一篇

猜你喜欢

热点阅读