我们考虑这么一个问题:建房子。假设建房子有三个步骤:修地基,砌墙,砌屋顶。有很多种类的房子,但是建造的过程是相同的:那么假设想用一个传统方式进行建房子:
首先定义一个commonHouse继承自基类AbstractHouse并且重写修房子的三种方法。然后有一个客户端去调用这个commonhouse的方法实现:
package com.builder;
public abstract class AbstractHouse {
//打地基
public abstract void buildBasic();
//砌墙
public abstract void buildWalls();
//封顶
public abstract void roofed();
//整个过程如下
public void build(){
buildBasic();
buildWalls();
roofed();
}
}
对于某一个具体的房子的修建:
package com.builder;
public class CommonHouse extends AbstractHouse{
@Override
public void buildBasic() {
System.out.println("给普通房子打地基");
}
@Override
public void buildWalls() {
System.out.println("给普通房子砌墙");
}
@Override
public void roofed() {
System.out.println("给普通房子封顶");
}
}
那么当我们建造房子的时候调用客户端进行修建房子:
package com.builder;
public class Client {
public static void main(String[] args){
CommonHouse commonHouse = new CommonHouse();
commonHouse.build();
}
}
从传统的角度,这是一个非常容易理解和简单的操作。但是不利于程序的拓展维护,也就是说,产品(房子)和创建产品的过程(build下面调用的三个函数)封装在了一起,也就是这两个东西耦合性过强了。所以要用到建造者模式,将产品和产品的构建过程解耦。建造者模式把复杂对象的过程抽象出来,使这个抽象过程的不同实现方式可以构造出不同属性的对象。
在这个建造者模式中,House是一个产品,他和HouseBuilder聚合。HouseBuilder本身是一个抽象类,他抽象了整个盖房子的过程,包括了最后的返回的结果build返回了一个产品House. 然后底下有两个与HouseBuilder泛化关系的具体实现类CommonHouse和HighBuilding。HouseDirector是和HouseBuilder是聚合关系,它负责控制什么时候调用HouseBuilder建房子。Client作为主程序去调用HouseDirector.
首先来看看产品house:
package com.builder.improve;
public class House {
private String base;
private String wall;
private String roofed;
public String getBase() {
return base;
}
public void setBase(String base) {
this.base = base;
}
public String getWall() {
return wall;
}
public void setWall(String wall) {
this.wall = wall;
}
public String getRoofed() {
return roofed;
}
public void setRoofed(String roofed) {
this.roofed = roofed;
}
}
House这个产品就是有他自己的属性。之后定义一个抽象类HouseBuilder这个类里面定义了建房子的全过程:
package com.builder.improve;
//抽象建造者,需要把建造的流程规定清楚
public abstract class HouseBuilder {
protected House house = new House();
public abstract void buildBasic();
public abstract void buildWalls();
public abstract void roofed();
//建造房子好后,将产品返回
public House buildHouse(){
return house;
}
}
然后就是抽象类的两种具体实现:
package com.builder.improve;
public class CommonHouse extends HouseBuilder{
@Override
public void buildBasic() {
System.out.println("普通房子打地基5m");
}
@Override
public void buildWalls() {
System.out.println("普通房子砌墙10cm");
}
@Override
public void roofed() {
System.out.println("普通房子砌普通房顶");
}
}
package com.builder.improve;
public class HighBuilding extends HouseBuilder{
@Override
public void buildBasic() {
System.out.println("高楼打地基100m");
}
@Override
public void buildWalls() {
System.out.println("高楼砌墙20cm");
}
@Override
public void roofed() {
System.out.println("高楼砌透明屋顶");
}
}
之后定义一个HouseDirector来负责具体建房子的具体流程:
package com.builder.improve;
public class HouseDirector {
HouseBuilder houseBuilder = null;
public HouseDirector(HouseBuilder houseBuilder) {
this.houseBuilder = houseBuilder;
}
//如何处理建造房子的流程交给指挥者HouseDirector
public House constructHouse(){
houseBuilder.buildBasic();
houseBuilder.buildWalls();
houseBuilder.roofed();
return houseBuilder.buildHouse();
}
}
最后就是一个客户端决定什么时候盖房子了:
package com.builder.improve;
public class Client {
public static void main(String[] args){
CommonHouse commonHouse = new CommonHouse();
HouseDirector houseDirector = new HouseDirector(commonHouse);
House house = houseDirector.constructHouse();
HighBuilding highBuilding = new HighBuilding();
HouseDirector houseDirector1 = new HouseDirector(highBuilding);
houseDirector1.constructHouse();
}
}
从这个Client可以看出,当想调用一个建造者进行建房子的时候只需要先构建一个HouseBuilder完成盖房子的步骤,然后调用具体的HouseDirector来完成盖房子已经定义好的动作即可。
当如果有一个新的OtherHouse类型想要添加的时候,我们只需要做两件事情:首先在抽象类HouseBuilder上面继承新的房子类,然后在Client上面调用这个新的类即可,非常方便,易于拓展,符合开闭原则。但是需要注意的是,如果产品之间差异很大,则不适合建造者模式。
建造者模式核心是把修房子的三个步骤的定义,和修房子的创建过程constructHouse这个步骤分离出来。