• 设计模式——建造者模式


    引言

    之前在家看两个小外甥玩轨道车,拆开包装,一堆小零件,兄弟两一个拼桥梁、弯道、路标,一个装车、搭立交、组装上下坡。不一会儿轨道就全拼好了,两兄弟用代表自己的车子在轨道上追逐,玩的很开心。我看了下轨道车包装,根据使用零件多少不同,组拼顺序不同,摆放不同可以创建不同的轨道和街道,有椭圆形的,上下立交式的,单层的……

    忽然想到用程序来表述玩轨道车的流程,如果用类图描述轨道车的玩法,可以简单表示为:

    分为两个部分:

    红色为轨道车的各个部件,Road规定了轨道车可以有 坡度、弯道、桥梁、路标、汽车、立交这几个部分;

    蓝色部分为建造不同的轨道,环形轨道(AnnularBuilder)和立交轨道(InterchangeBuilder)。

    Road为模板方法的变形形式,轨定轨道车的部件和各个部件的组装顺序,实现如下:

    public abstract class Road {
        //坡度
        protected abstract void slope();
        //弯道
        protected abstract void curve();
        //桥梁
        protected abstract void bridge();
        //路标
        protected abstract void guide();
        //汽车
        protected abstract void car();
        //立交
        protected abstract void interchange();
    
        private List<String> list = new ArrayList<>();
    
        final public void create() throws InvocationTargetException, IllegalAccessException {
            Method[] methods = this.getClass().getDeclaredMethods();
            for (String method : list) {
                for (int i = 0; i < methods.length; i++) {
                    if (methods[i].getName().equals(method)) {
                        methods[i].invoke(this, null);
                    }
                }
            }
        }
    
        final public void setList(List<String> methods){
            this.list = methods;
        }
    }

    组装轨道车的部件实现方法:

    public class TrackRoad extends Road {
        //坡度
        @Override
        protected void slope() {
            System.out.println("建造上下坡……");
        }
    
        //弯道
        @Override
        protected void curve() {
            System.out.println("建造曲线车道……");
        }
    
        //桥梁
        @Override
        protected void bridge() {
            System.out.println("建造桥梁……");
        }
    
        //路标
        @Override
        protected void guide() {
            System.out.println("放置公路路标……");
        }
    
        //汽车
        @Override
        protected void car() {
            System.out.println("建造汽车……");
        }
    
        //立交
        @Override
        protected void interchange() {
            System.out.println("建造立交……");
        }
    }

    抽象创建轨道车类Builder定义了轨道车的组装部件和获取组装的轨道车

    public abstract class Builder {
        /**
         * 不同部件的创建
         */
        public abstract void setPart(List<String> methods);
    
        /**
         * 建造轨道
         */
        public abstract TrackRoad buildRoad() throws InvocationTargetException, IllegalAccessException;
    }

    具体轨道车玩法建造类(立交轨道车):

    public class InterchangeBuilder extends Builder {
        private TrackRoad road = new TrackRoad();
        @Override
        public void setPart(List<String> methods) {
            this.road.setList(methods);
        }
    
        @Override
        public TrackRoad buildRoad() {
            return this.road;
        }
    }

    如果想创建一个立交轨道,可以这么创建:

    InterchangeBuilder interchangeBuilder = new InterchangeBuilder();
    List<String> interMethods = new ArrayList<>();
    interMethods.add("slope");
    interMethods.add("bridge");
    interMethods.add("guide");
    interMethods.add("interchange");
    interMethods.add("car");
    interchangeBuilder.setPart(interMethods);
    interchangeBuilder.buildRoad().create();

    建造上下坡……
    建造桥梁……
    放置公路路标……
    建造立交……
    建造汽车……

    引入导演类

    坡度、弯道、桥梁、路标、汽车、立交不同组装方式可以构造不同的轨道,为了方便支持的很多不同的轨道,可以增加个导演类(Director)。

    导演类封装立交轨道和环形轨道的实现,对外提供直接获取的方法:

    public class Director {
        private List<String> steps = new ArrayList<>();
        private InterchangeBuilder interchangeBuilder = new InterchangeBuilder();
        private AnnularBuilder annularBuilder = new AnnularBuilder();
    
        public TrackRoad getInterchangeBuilder(){
            System.out.println("===========================建造立交车道===========================");
            this.steps.clear();
            this.steps.add("slope");
            this.steps.add("bridge");
            this.steps.add("guide");
            this.steps.add("interchange");
            this.steps.add("car");
            this.interchangeBuilder.setPart(this.steps);
            return this.interchangeBuilder.buildRoad();
        }
    
        public TrackRoad getAnnularBuilder(){
            System.out.println("===========================建造曲线车道===========================");
         this.steps.clear();
    this.steps.add("curve"); this.steps.add("bridge"); this.steps.add("guide"); this.steps.add("car"); this.annularBuilder.setPart(this.steps); return this.annularBuilder.buildRoad(); } }

    客户端不关注如何实现,只需要拿来即用(可玩):

        public void testDerictor() throws InvocationTargetException, IllegalAccessException {
            Director director = new Director();
            director.getAnnularBuilder().create();
    
            director.getInterchangeBuilder().create();
        }

    其实这就是建造者模式,由导演类决定如何构建具体的对象(产品)。

    建造者模式

    定义

      将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

    通用类图

    四要素

    建造者模式中有以下4个角色:

    Product产品类

    通常是实现模板方法模式(有模板方法和基本方法的类),例子里的TrackRoad(轨道)就属于产品类。

    Builder抽象建造者

    规范产品的组建,一般是抽象类,约定功能由子类去实现具体的建造方法,对应例子里的Builder。

    ConcreteBuilder具体建造者

    实现抽象建造者的所有方法。例子里的InterchangeBuilder和AnnularBuilder就是具体轨道的建造者。

    Director导演类

    封装具体建造者,提供简单易用的构建产品类方法。

    总结

    优点

    封装性:将产品本身与产品创建过程进行解耦,可以使用相同的创建过程来得到不同的产品。也就说细节依赖抽象。

    建造者独立,容易扩展:增加新的具体建造者无需修改原有类库的代码,易于拓展,符合“开闭原则“。

    缺点

    建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。

    使用场景

    • 相同的方法,不同的执行顺序,产生不同的事件结果时
    • 多个部件或零件都可以装配到一个对象中,但是产生的运行结果又不相同时
    • 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能

    本文代码

    demo地址

  • 相关阅读:
    洛谷P1586 四方定理
    洛谷P3807 【模板】卢卡斯定理exgcd
    扩展中国剩余定理详解
    HDU 1573 X问题
    POJ 2891 Strange Way to Express Integers
    中国剩余定理详解
    java.lang.UnsupportedClassVersionError: Bad version number in .class file 解决方案
    MySQL对于有大量重复数据表的处理方法
    【一牛鸣】下周或触发新变盘9.16
    Django里面的RequestContext
  • 原文地址:https://www.cnblogs.com/mr-yang-localhost/p/9744580.html
Copyright © 2020-2023  润新知