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

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

建造者模式

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

举个栗子

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根据参数,能得到确定结果,而设计模式不是。看设计模式类的文章的时候,看到高赞或者高踩,都要看作者对这个模式的理解,没有带个人理解的,都是笔记(虽说我也写了几篇设计模式的笔记),而已。

水平有限,难免有错,还请评论区指责下
    原文作者:l_sivan
    原文地址: https://www.jianshu.com/p/4d2e22b3d2ef
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞