设计模式学习-建造者模式

纵然是瞬间 提交于 2020-03-04 06:30:09

建造者模式

定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以产生不同的表示

1. 应用场景

  1. 复杂对象中,相同的方法,不同的执行顺序,会产生较大的差异。希望能够按不同的顺序调用对象的方法。
  2. 复杂对象的组成部分时常可能发生变化,但组装方法类似。比如零食套餐搭配,电脑的配置搭配等。

2.五个组成部分

  1. 抽象产品类
    定义产品具体业务逻辑方法和一个调度方法,该调度方法可以控制各个业务逻辑方法的执行顺序或者产品类的组成部分。可以设置一个集合存储方法执行顺序或者零件类型。
  2. 具体产品类
    产品类实现具体业务逻辑的方法。差异性很大的产品不适合使用建造者模式。产品类通常可以结合模板方法模式。
  3. 抽象建造者
    • 一个抽象方法设置产品的不同组成部分或者设置不同方法的执行顺序。
    • 一个抽象方法构建产品并返回
  4. 具体的建造者
    继承抽象建造者,每个类型的产品都需要一个具体的建造者。该类返回一个对应的产品
  5. 导演类
    调度不同的建造者,来建造出不同的产品。场景类只需要和导演类打交道

类图如下(此处产品类是模板方法模式的类图):
在这里插入图片描述

3.案例模拟

需求:现在需要组装两种车,宝骏和宝马,两者组装顺序不同。宝马:底盘->轮子->车身->座椅,宝骏:底盘->车身->座椅->轮子,还有进化版的宝骏,不要轮子,直接就能飞,敞篷宝马,不要车身,底盘轮子座椅直接开

  1. 先创建一个抽象产品类和两个实现的产品类宝骏和宝马产品。使用了模板方法的模式
  • 抽象产品类:
public  abstract class AbstractCar {
    private ArrayList<String> sequence=new ArrayList<String>();
    final public void setSequence(ArrayList<String> sequence){
        this.sequence=sequence;
    }
    protected abstract void setChassis(); //组装底盘
    protected abstract void setWheel();//组装轮子
    protected abstract void setBody();//组装车身
    protected abstract void setSeat(); //组装座椅
    //按要求的顺序执行方法
    protected void build(){
        for (String s : sequence) {
            switch (s){
                case "chassis":this.setChassis();break;
                case "wheel":this.setWheel();break;
                case "body":this.setBody();break;
                case "seat":this.setSeat();break;
            }
        }
        System.out.println(this.getClass().getName()+"已生产完成--------------");
    }
}
  • 宝骏类:
public class WagonCar extends AbstractCar {
    @Override
    protected void setChassis() {
        System.out.println("宝骏的地盘装好了---------------------");
    }
    @Override
    protected void setWheel() {
        System.out.println("宝骏的轮子装好了----------------------");
    }
    @Override
    protected void setBody() {
        System.out.println("宝骏的车身装好了----------------------");
    }
    @Override
    protected void setSeat() {
        System.out.println("宝骏的座椅装好了---------------------");
    }
}
  • 宝马类:
public class BMWCar extends AbstractCar {
    @Override
    protected void setChassis() {
        System.out.println("宝马的地盘装好了---------------------");
    }
    @Override
    protected void setWheel() {
        System.out.println("宝马的轮子装好了---------------------");
    }
    @Override
    protected void setBody() {
        System.out.println("宝马的车身装好了---------------------");
    }
    @Override
    protected void setSeat() {
        System.out.println("宝马的座椅装好了---------------------");
    }
}
  1. 创建一个抽象建造者类和两个实现类,分别是宝马建造者和宝骏建造者
  • 抽象建造者
public abstract class AbstractBuilder {
     //一个方法设置抽象类中的方法执行顺序
    public abstract void setSequence(ArrayList<String> sequence);
    //一个方法返回建造的产品
    public abstract AbstractCar getCar();
}
  • 宝骏建造者
public class WagonBuilder extends AbstractBuilder{
    private WagonCar wagon=new WagonCar();

    @Override
    //设置宝骏的组装顺序
    public void setSequence(ArrayList<String> sequence) {
        this.wagon.setSequence(sequence);
    }
    @Override
    public AbstractCar getCar() {
        return this.wagon;
    }
}
  • 宝马建造者
public class BMWBuilder extends AbstractBuilder {

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

    @Override
    public AbstractCar getCar() {
        return bmw;
    }
}
  1. 创建一个导演类。根据需求,调度各个建造者进行生产,有多少需求就在导演类中写多少个方法,返回需要的产品。这样场景类就可以直接调用对应方法获得需要的产品。后期增加需求直接在导演类中增加代码,生产出需要的产品。
  • 导演类
public class Director {
    public ArrayList<String> sequence=new ArrayList<>();
    private AbstractBuilder wagonBuilder=new WagonBuilder();
    private AbstractBuilder BMBuilder=new BMWBuilder();
    //需求一:生产一个进化版宝骏,不用轮子的
    public WagonCar getSupperWagon(){
        sequence.clear();
        sequence.add("chassis");
        sequence.add("body");
        sequence.add("seat");
        wagonBuilder.setSequence(sequence);
        return (WagonCar) wagonBuilder.getCar();
    }
    //需求二:生产一个普通宝骏
    public WagonCar getWagon(){
        sequence.clear();
        sequence.add("chassis");
        sequence.add("body");
        sequence.add("seat");
        sequence.add("wheel");
        wagonBuilder.setSequence(sequence);
        return (WagonCar) wagonBuilder.getCar();
    }
    //需求三:生产一个普通宝马,宝马先装底盘轮子,再装车身和座椅
    public BMWCar getBMW(){
        sequence.clear();
        sequence.add("chassis");
        sequence.add("wheel");
        sequence.add("body");
        sequence.add("seat");
        BMBuilder.setSequence(sequence);
        return (BMWCar) BMBuilder.getCar();
    }
    //需求三:生产一个敞篷宝马,宝马先装底盘轮子,再装座椅,不装车身
    public BMWCar getOpenBMW(){
        sequence.clear();
        sequence.add("chassis");
        sequence.add("wheel");
        sequence.add("seat");
        BMBuilder.setSequence(sequence);
        return (BMWCar) BMBuilder.getCar();
    }
}

4.代码测试。

  1. 如果不适用建造者模式,每次都要new一个车对象,再设置组装顺序然后建造
 @Test
    /**
     * Description: 直接生产宝骏,不用建造者
     */
    public void test(){
        WagonCar wagonCar = new WagonCar();
        //组装顺序集合
        ArrayList<String> sq = new ArrayList<>();
        sq.add("chassis");
        sq.add("body");
        sq.add("wheel");
        sq.add("seat");
        wagonCar.setSequence(sq);
        //开始生产宝骏
        wagonCar.build();
        /**
         * 宝骏的地盘装好了---------------------
         * 宝骏的车身装好了----------------------
         * 宝骏的轮子装好了----------------------
         * 宝骏的座椅装好了
         * builderTest.WagonCar已生产完成--------------
         */
        //此时如果生产宝骏的顺序发生改变了怎么办,又要重新创建一个宝骏类并设置组装顺序
    }
  1. 如果使用了建造者(不使用导演类),只需要把一个组装顺序给建造者,就能生产符合要求的车
/**
     * Description:使用建造者生产宝骏
     */
    @Test
    public void test2(){
        WagonBuilder wagonBuilder = new WagonBuilder();
        //组装顺序集合
        ArrayList<String> sq = new ArrayList<>();
        sq.add("chassis");
        sq.add("body");
        sq.add("wheel");
        sq.add("seat");
        //给建造者指定组装顺序1
        wagonBuilder.setSequence(sq);
        AbstractCar wagon1 = wagonBuilder.getCar();
        wagon1.build();

        System.out.println("进化版宝骏,不要轮子");
        //给建造者指定组装顺序2;而且不要轮子了,直接飞
        ArrayList<String> sq2 = new ArrayList<>();
        sq2.add("chassis");
        sq2.add("seat");
        sq2.add("body");
        wagonBuilder.setSequence(sq2);
        AbstractCar wagon2 = wagonBuilder.getCar();
        wagon2.build();
        /**
         宝骏的地盘装好了---------------------
         宝骏的车身装好了----------------------
         宝骏的轮子装好了----------------------
         宝骏的座椅装好了
         builderTest.WagonCar已生产完成--------------
         进化版宝骏
         宝骏的地盘装好了---------------------
         宝骏的座椅装好了
         宝骏的车身装好了----------------------
         builderTest.WagonCar已生产完成--------------
         */
    }
  1. 如果使用了导演类,高层模块就可以直接创建导演类,生产出所需要的产品,不过产品需求已经在导演类中写好。
@Test
    /**
     * Description:使用导演类创建所需的汽车,调用者不需要关系具体由谁生产,怎么生产
     */
    public void test3(){
        Director director = new Director();
        System.out.println("-----------//生产普通宝马-------------");
        BMWCar bmw = director.getBMW();
        bmw.build();

        System.out.println("------------ //生产普通宝骏------------");
        WagonCar wagon = director.getWagon();
        wagon.build();

        System.out.println("----------//生产超级宝骏--------------");
        WagonCar supperWagon = director.getSupperWagon();
        supperWagon.build();

        System.out.println("-----------//生产敞篷宝马-------------");
        BMWCar openBMW = director.getOpenBMW();
        openBMW.build();

        /**
         -----------//生产普通宝马-------------
         宝马的地盘装好了---------------------
         宝马的轮子装好了---------------------
         宝马的车身装好了---------------------
         宝马的座椅装好了---------------------
         builderTest.BMWCar已生产完成--------------
         ------------ //生产普通宝骏------------
         宝骏的地盘装好了---------------------
         宝骏的车身装好了----------------------
         宝骏的座椅装好了---------------------
         宝骏的轮子装好了----------------------
         builderTest.WagonCar已生产完成--------------
         ----------//生产超级宝骏--------------
         宝骏的地盘装好了---------------------
         宝骏的车身装好了----------------------
         宝骏的座椅装好了---------------------
         builderTest.WagonCar已生产完成--------------
         -----------//生产敞篷宝马-------------
         宝马的地盘装好了---------------------
         宝马的轮子装好了---------------------
         宝马的座椅装好了---------------------
         builderTest.BMWCar已生产完成--------------
         */
    }

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!