zoukankan      html  css  js  c++  java
  • 设计模式——建造者模式

    引言

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

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

    分为两个部分:

    红色为轨道车的各个部件,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地址

  • 相关阅读:
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31
    知也atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31无涯 - I
  • 原文地址:https://www.cnblogs.com/mr-yang-localhost/p/9744580.html
Copyright © 2011-2022 走看看