美文网首页
Java设计模式之建造者模式

Java设计模式之建造者模式

作者: CoderJed | 来源:发表于2018-09-25 16:04 被阅读0次

    因为我们公司制造的悍马汽车得到了客户的满意(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类,这个类是做了层封装,类中的方法说明如下:

    • A 型号的奔驰车辆模型是只有启动(start)、停止(stop)方法,其他的引擎声音、喇叭都没有;
    • B 型号的奔驰车是先发动引擎(engine boom),然后启动(star),再然后停车(stop),没有喇叭;
    • C 型号的宝马车是先喇叭叫一下(alarm),然后(start),再然后是停车(stop),引擎不轰鸣;
    • D 型号的宝马车就一个启动(start),然后一路跑到黑,永动机,没有停止方法,没有喇叭,没有引擎轰鸣;
    • E 型号、F 型号...等等,可以有很多,启动(start)、停止(stop)、喇叭(alarm)、引擎轰鸣(engineBoom)这四个方法在这个类中可以随意的自由组合,这里都可以实现,我们就以前4种举例说明。
    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();
            }
        }
    
    }
    

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

    • Client 就是客户,这个到具体的应用中就是其他的模块或者页面;
    • CarModel 以及两个实现类 BenzModel 和 BMWModel 叫做产品类(Product Class),这个产品类实现了模板方法模式,也就是有模板方法和基本方法,这个参考上一节的模板方法模式
    • CarBuilder 以及两个实现类 BenzBuilder 和 BMWBuilder 叫做建造者(Builder Class);
    • Director 类叫做导演类(Director Class),负责安排已有模块的顺序,然后告诉 Builder 开始建造。

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

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

    相关文章

      网友评论

          本文标题:Java设计模式之建造者模式

          本文链接:https://www.haomeiwen.com/subject/vcginftx.html