设计模式之禅6

来源:互联网 发布:无线点菜机软件 编辑:程序博客网 时间:2024/06/05 02:53

设计模式之禅6

真刀实枪之建造者模式

  • 变化是永恒的--悍马车的私人订制

    • 汽车的启动,停止,喇叭声音,引擎声音都有客户控制
    • 先看类图吧,简单设计下:顺序如何由sequence来决定
    • 代码

      • CarModel抽象类

        package com.peng.builder;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月16日 * @description */public abstract class CarModel {    private ArrayList<String> sequence=new ArrayList<String>();F    // 发动车    public abstract void start();    // 停车    public abstract void stop();    // 响喇叭    public abstract void alarm();    // 引擎    public abstract void engineBoom();    //    // 运行    final public  void run() {        for(String s:sequence){            if("start".equals(s)){                this.start();            }else if("stop".equals(s)){                this.stop();            }else if("alarm".equals(s)){                this.alarm();            }else if("engineBoom".equals(s)){                this.engineBoom();            }        }    }    //把传递过来的值传递到类中    final public void setSequence(ArrayList<String> sequence){        this.sequence=sequence;    }}
      • 悍马类

        package com.peng.builder;/** * @author kungfu~peng * @data 2017年11月16日 * @description */public class HummerCarModel extends CarModel {    @Override    public void start() {        System.out.println("悍马跑起来!");    }    @Override    public void stop() {        System.out.println("悍马停车!");    }    @Override    public void alarm() {        System.out.println("悍马的喇叭声!");    }    @Override    public void engineBoom() {        System.out.println("悍马的引擎发动!");    }}
      • 测试类

        package com.peng.builder;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月16日 * @description */public class Test {    public static void main(String[] args) {        // 创建悍马车模型        HummerCarModel hummer = new HummerCarModel();        // 创建执行顺序        ArrayList<String> list = new ArrayList<String>();        list.add("start");        list.add("alarm");        list.add("engineBoom");        list.add("stop");        // 按客户的顺序执行        hummer.setSequence(list);        hummer.run();    }}   
      • 上述代码中,汽车的动作的执行顺序是可以随意指定的,我们也只满足了这一个条件而已,还有下一个下下一个需求...直到把你逼疯为之。那怎么办,我们写场景类来一个个的控制吗,显然是不合理的。有了,我们为模型产品模型定义一个建造者,你要啥顺序直接告诉建造者,由建造者来建造。
      • 改造的类图
        • 如类图,增加了一个CarBuilder抽象类,由他来组装各个车模

          • CarBuilder

            package com.peng.builder;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月16日 * @description */public abstract class CarBuilder {    // 建造一个模型,提供一个组装顺序    public abstract void setSequence(ArrayList<String> sequence);    // 获得车辆模型    public abstract CarModel getCarModel();}
          • HummerBuilder

            package com.peng.builder;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月16日 * @description */public class HummerBuilder extends CarBuilder {    private HummerCarModel hummer = new HummerCarModel();    @Override    public void setSequence(ArrayList<String> sequence) {        this.hummer.setSequence(sequence);    }    @Override    public CarModel getCarModel() {        return hummer;    }}
          • CarModel

            package com.peng.builder;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月16日 * @description */public abstract class CarModel {    private ArrayList<String> sequence = new ArrayList<String>();    // 发动车    public abstract void start();    // 停车    public abstract void stop();    // 响喇叭    public abstract void alarm();    // 引擎    public abstract void engineBoom();    //    // 运行    final public void run() {        for (String s : sequence) {            if ("start".equals(s)) {                this.start();            } else if ("stop".equals(s)) {                this.stop();            } else if ("alarm".equals(s)) {                this.alarm();            } else if ("engineBoom".equals(s)) {                this.engineBoom();            }        }    }    // 把传递过来的值传递到类中    final public void setSequence(ArrayList<String> sequence) {        this.sequence = sequence;    }}
          • HummerCarModel

            package com.peng.builder;/** * @author kungfu~peng * @data 2017年11月16日 * @description */public class HummerCarModel extends CarModel {    @Override    public void start() {        System.out.println("悍马跑起来!");    }    @Override    public void stop() {        System.out.println("悍马停车!");    }    @Override    public void alarm() {        System.out.println("悍马的喇叭声!");    }    @Override    public void engineBoom() {        System.out.println("悍马的引擎发动!");    }}
          • 测试类

            package com.peng.builder;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月16日 * @description */public class Test {    public static void main(String[] args) {        // 创建执行顺序        ArrayList<String> list = new ArrayList<String>();        list.add("start");        list.add("alarm");        list.add("engineBoom");        list.add("stop");        HummerBuilder hb = new HummerBuilder();        hb.setSequence(list);        // 获得悍马车        HummerCarModel hummer = (HummerCarModel) hb.getCarModel();        // 执行hummer的run方法        hummer.run();    }}
      • 同样的顺序的悍马车也制造出来了,而且代码也比之间访问简单了许多,在做项目的过程中,需求是个无底洞。客户是上帝,我们不能预知他们的顺序, 那该怎么办?封装一下,找一个导演,指挥各个事件的先后顺序,然后为每种顺序指定一个代码,然后你说一种我们立刻生产处理。

        • 类图如下
        • 代码

          • Direct类

            package com.peng.builder;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月16日 * @description */public class Director {    private ArrayList<String> sequence = new ArrayList<String>();    private HummerBuilder hb = new HummerBuilder();    // 获得悍马1    public CarModel getHummerCarModel1() {        // 清空列表        sequence.clear();        sequence.add("start");        sequence.add("alarm");        sequence.add("engineBoom");        sequence.add("stop");        hb.setSequence(sequence);        return hb.getCarModel();    }    // 获得悍马2    public CarModel getHummerCarModel2() {        // 清空列表        sequence.clear();        sequence.add("alarm");        sequence.add("engineBoom");        sequence.add("start");        sequence.add("stop");        hb.setSequence(sequence);        return hb.getCarModel();    }    // 获得悍马3    public CarModel getHummerCarModel3() {        // 清空列表        sequence.clear();        sequence.add("stop");        sequence.add("start");        sequence.add("alarm");        sequence.add("engineBoom");        hb.setSequence(sequence);        return hb.getCarModel();    }}
          • 测试类(Client用test来写~~)

            package com.peng.builder;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月16日 * @description */public class Test {    public static void main(String[] args) {        // 创建导演        Director director = new Director();        // 获得悍马车1        HummerCarModel hummer1 = (HummerCarModel) director.getHummerCarModel1();        // 执行hummer的run方法        System.out.println("悍马车1~~~~~");        hummer1.run();        // 获得悍马车2        HummerCarModel hummer2 = (HummerCarModel) director.getHummerCarModel2();        // 执行hummer的run方法        System.out.println("悍马车2~~~~~");        hummer2.run();        // 获得悍马车3        HummerCarModel hummer3 = (HummerCarModel) director.getHummerCarModel3();        // 执行hummer的run方法        System.out.println("悍马车3~~~~~");        hummer3.run();    }}
        • 清晰吧,简单吧,我们写程序的最终目的是:简单清晰。代码是让人看的,不是写完就完了。

建造者模式的定义

  • Builder Pattern
  • 也叫做生成器模式
  • Separate the construction of a complex object from its representation so that same construction process can create different representations(将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示)
  • 通用类图
    • 建造者中有四个角色

      1. Product产品类2. Builder抽象建造者类3. ConcreteBuilder具体建造者类4. Director导演类
  • 通用代码
    • 产品类

      public class Product{    public void doSomething(){        //独立业务处理    }}
    • 抽象建造者类

      public abstract class Builder{    //设置产品的不同部分,以获得不同的产品    public abstract void setPart();    //建造产品    public abstract Product buildProduct();}
    • 具体建造者类

      public class ConcreteProduct extends Builder{    private Product product=new Product();    //设置产品零件    public void setPart(){        //产品类的逻辑处理    }    //组建一个产品    public Product buildProduct(){        return product;    }}
    • 导演类

      public class Direct{    private Builder builder=new ConcreteBuilder();    //构建不同的产品    public Product getAProduct(){        builder.setPart();        return builder.buildProduct();    }}

建造者模式的应用

  • 建造者模式的优点

    1. 封装性2. 建造者独立,容易扩展3. 便于控制细节风险
  • 建造者模式的使用场景

    1. 相同的方法,不同的执行顺序,产生不同的执行结果2. 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同3. 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能4. 在创建对象的过程中会使用到系统中的一些其他对象,这些对象在产品对象的创建过程中,不易得到时--这种方法只是一个补偿方法,因为一个对象不容易获得,而在设计阶段竟然没有发觉,而要通过创建者模式柔化创建过程,本身已经违反了设计的最初目标

建造者的注意事项

  • 关注零件类型和装配的工艺(顺序),这是它与工厂方法的最大的不同地方

扩展

  • 建造者模式+模板模式(比如加入导演类的悍马的生产过程中)
  • 建造者的核心思想:零件的组装,组装的顺序不同,效能也不同
  • 与工厂模式的对比
    • 工厂模式的任务是对对象的创建感兴趣,如何创建的细节并不关心
    • 建造者模式的最主要的功能是基本方法的调用顺序安排,也就是这些基本的方法已经实现了,通俗的讲也就是零件的装配,顺序的不同产生的对象也不同。
    • 工厂模式的重点是创建,,创建零件是它关心的,组装是它所不关心的

最佳实践

  • 【建造者模式+模板模式】记得用哦!
  • 别孤立的使用一个模式,僵化的使用一个模式会让你受害无穷

声明

  • 摘自秦小波《设计模式之禅》第2版;
  • 仅供学习,严禁商业用途;
  • 代码手写,没有经编译器编译,有个别错误,自行根据上下文改正。
原创粉丝点击