前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java设计模式之建造者模式

Java设计模式之建造者模式

作者头像
CoderJed
发布2018-09-30 10:21:46
4190
发布2018-09-30 10:21:46
举报
文章被收录于专栏:Jed的技术阶梯Jed的技术阶梯

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

代码如下:

代码语言:javascript
复制
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;
    }
    
}
代码语言:javascript
复制
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()...");
    }

}
代码语言:javascript
复制
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个奔驰车,要求跑的时候,先发动引擎,然后再挂档启动,然后停下来,不需要喇叭,代码这样实现:

代码语言:javascript
复制
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()...

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

代码如下:

代码语言:javascript
复制
public abstract class CarBuilder {
    
    public abstract void setSequence(ArrayList<String> sequence);
    public abstract Car getCar();

}
代码语言:javascript
复制
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;
    }

}
代码语言:javascript
复制
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;
    }

}
代码语言:javascript
复制
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种举例说明。
代码语言:javascript
复制
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类型的不要:

代码语言:javascript
复制
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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.09.25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档