设计模式(六)——建造者模式

作者: l_sivan | 来源:发表于2017-03-30 10:18 被阅读70次

    本文属于系列文章《设计模式》,附上文集链接

    建造者模式

    • 定义:将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
    • 要解决的问题:看定义就看到了,首先,针对的问题是复杂对象的构建,其次,对这些复杂的构建还可以存在不同的结果。
    • 属于创建类模式

    举个栗子

    builder,看到这个词的第一印象就是工地里的建造者(最近刚好学校新建宿舍楼,天天见),然后嘛,工人要做的事,就是要建一栋宿舍楼,这就是构建一个复杂的对象。而建宿舍这件事的构建过程是相同的,但是新建的宿舍楼是要男女混住的,里面的具体构造还不一样(女生宿舍楼梯口装摄像头防狼贼。。),宿舍名也不一样,所以相同的构造过程得到不同的结果,就来实现这个栗子来玩一下。
    要注意到的是,这里的明确需求,只是得到一个宿舍楼。

    先用一下假设性原则,不然都体会不了这个模式的好处,我们先假设,不用这个模式要怎么实现这个需求。
    代码:

    // 抽象宿舍类,定义宿舍楼具有的几个属性
    public abstract class Dormitory {
        // 地基
        protected String foundation;
        // 宿舍的摄像头
        protected String cameraOnStairway;
        // 是否需要装摄像头要
        protected boolean needCamera;
        // 宿舍颜色
        protected String dormitoryColor;
        public void setFoundation(String foundation) {
            this.foundation = foundation;
        }
        public void setCameraOnStairway(String cameraOnStairway) {
            if(needCamera == true){
                this.cameraOnStairway = cameraOnStairway;
            }
        }
        public void setNeedCamera(boolean needCamera) {
            this.needCamera = needCamera;
        }
        public void setDormitoryColor(String dormitoryColor) {
            this.dormitoryColor = dormitoryColor;
        }
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder("这个"+this.getClass().getSimpleName()+"宿舍楼,");
            sb.append(foundation+",");
            if(needCamera == true){
                sb.append(cameraOnStairway+",");
            }else{
                sb.append("不需要装摄像头,");
            }
            sb.append(dormitoryColor);
            return sb.toString();
        }
    }
    **********
    // 男生宿舍
    public class ManDormitory extends Dormitory{}
    // 女生宿舍
    public class WomanDormitory extends Dormitory {}
    ***********
    // 场景类
    public class Client {
        public static void main(String[] args) {
            Dormitory manDormitory = new ManDormitory();
            manDormitory.setFoundation("打了一个坚实的地基");
            manDormitory.setNeedCamera(false);
            manDormitory.setCameraOnStairway("装了一个摄像头");
            manDormitory.setDormitoryColor("外表是酷酷的蓝色");
            System.out.println(manDormitory);
            System.out.println("-------------------------------------");
            Dormitory womanDormitory = new WomanDormitory();
            womanDormitory.setFoundation("打了一个坚实的地基");
            womanDormitory.setNeedCamera(true);
            womanDormitory.setCameraOnStairway("装了一个酷酷的摄像头");
            womanDormitory.setDormitoryColor("外表是萌萌的粉色");
            System.out.println(womanDormitory);
        }
    }
    结果:
    这个ManDormitory宿舍楼,打了一个坚实的地基,不需要装摄像头,外表是酷酷的蓝色
    -------------------------------------
    这个WomanDormitory宿舍楼,打了一个坚实的地基,装了一个酷酷的摄像头,外表是萌萌的粉色
    

    如无意外,到这里可能就看下去了,因为这完全不是建造者模式,完全是一个new。但我问一句,如果没看设计模式的东西,会觉得这个东西有很大很大的问题吗?对嘛,初学者,谁新建对象不是new的,得到结果就行了,完全不考虑扩展。
    在这里我很想说一句话就是,设计模式和面向对象的东西,首先要明白面向对象六大原则出现的目的是什么,要解决什么问题,否则,设计模式不就成了迂腐的教规了?面向对象是为了更好的解决需求变化的问题, 然后在变化的点,采用方法去拥抱这些变化。这才是最要紧要记住一个东西。所有的设计模式或者面向对象的所有原则都是奔向这个目的而去的。
    看回代码,在上面例子那里我就说了,要明确清楚的是,需求,只是得到宿舍楼,所以在场景类那里,直接new了男女两个宿舍,也并没有什么问题,确实实现了需求。但是考虑到变化的情况,假如有的男生宿舍楼处于学校外围,经常被盗,需要装摄像头,而有的女生宿舍处于学校中心,太安全了,不需要装摄像头,怎么办?这个就是需求变化的点,而如果使用上面那套代码,我们只能在场景类那里再new对象。每出现一个不同构建过程的对象,我们就new一个,疯狂new,问题就是这个,扩展性极其差。

    来用一下建造者模式

    // 抽象建造类
    public abstract class Builder {
        protected Dormitory dormitory;
        public abstract Dormitory buildDormitory();
    }
    // 负责建造男生宿舍的工人
    public class ManDormitoryBuilder extends Builder{
        public ManDormitoryBuilder() {
            super.dormitory = new ManDormitory();
        }
        @Override
        public Dormitory buildDormitory() {
            super.dormitory.setFoundation("打了一个坚实的地基");
            super.dormitory.setNeedCamera(false);
            super.dormitory.setCameraOnStairway("装了一个摄像头");
            super.dormitory.setDormitoryColor("外表是酷酷的蓝色");
            return super.dormitory;
        }
    }
    // 负责建造女生宿舍的工人
    public class WomanDormitoryBuilder extends Builder{
        public WomanDormitoryBuilder() {
            super.dormitory = new WomanDormitory();
        }
        @Override
        public Dormitory buildDormitory() {
            super.dormitory.setFoundation("打了一个坚实的地基");
            super.dormitory.setNeedCamera(true);
            super.dormitory.setCameraOnStairway("装了一个酷酷的摄像头");
            super.dormitory.setDormitoryColor("外表是萌萌的粉色");
            return super.dormitory;
        }
    }
    // 宿舍类都没有变化,这里就不列出来了
    // 场景类
    public class Client {
        public static void main(String[] args) {
            Builder manDormitoryBuilder = new ManDormitoryBuilder();
            Dormitory manDormitory = manDormitoryBuilder.buildDormitory();
            System.out.println(manDormitory);
            System.out.println("---------------");
            Builder womanDormitoryBuilder = new WomanDormitoryBuilder();
            Dormitory womanDormitory = womanDormitoryBuilder.buildDormitory();
            System.out.println(womanDormitory);
        }
    }
    结果:
    这个ManDormitory宿舍楼,打了一个坚实的地基,不需要装摄像头,外表是酷酷的蓝色
    \--------------------
    这个WomanDormitory宿舍楼,打了一个坚实的地基,装了一个酷酷的摄像头,外表是萌萌的粉色
    

    分析下代码:我们将new对象的过程封装到builder那里,builder类里有个dormitory属性,在子类builder构造函数予以实现,确保子类builder是对应的dormitory的生产对象。然后在子类builder的buildDormitory方法实现dormitory的构造过程。这么做有什么好处呢?我们的上层模块Client以后再面对下层模块Dormitory的变化时,就不用做出太大的改动了,比如上文中提到的新建两种宿舍,我们可以怎么做?可以直接在子类中重载方法buildDormitory,传入boolean参数来控制装不装摄像头,也可以直接在子类加方法,怎样的都行(扩展性啥的各自考虑啦),然后我们的上层模块Client都不需要再对这个Dormitory的构建过程有很大的了解(迪米特法则),我们只需要在Client中做好与Builder的“交涉”即可。

    后言:看了几篇博客,发现还是没看书这么好,博客往往直接将模式交代了就没了。还有发现一件事,就是看到有博客下面有评论说例子不正确啥的,但是我看了之后,其实无非就是方法的实现没有抽象好而已,而设计模式那个思想还是在那里的。所以我提醒自己,设计模式是一种思想,是一种方法,不是API这样的方法,API根据参数,能得到确定结果,而设计模式不是。看设计模式类的文章的时候,看到高赞或者高踩,都要看作者对这个模式的理解,没有带个人理解的,都是笔记(虽说我也写了几篇设计模式的笔记),而已。

    水平有限,难免有错,还请评论区指责下

    相关文章

      网友评论

        本文标题:设计模式(六)——建造者模式

        本文链接:https://www.haomeiwen.com/subject/lqyznttx.html