本文属于系列文章《设计模式》,附上文集链接
建造者模式
- 定义:将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
- 要解决的问题:看定义就看到了,首先,针对的问题是复杂对象的构建,其次,对这些复杂的构建还可以存在不同的结果。
- 属于创建类模式
举个栗子
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根据参数,能得到确定结果,而设计模式不是。看设计模式类的文章的时候,看到高赞或者高踩,都要看作者对这个模式的理解,没有带个人理解的,都是笔记(虽说我也写了几篇设计模式的笔记),而已。