1. 概述
建造者模式(生成器模式 Builder Pattern)是一种对象构造模式,他可以将复杂对象的建造过程抽象出来,使这个抽象过程的不同实现方法可以构造出不同表现的对象
建造者模式 是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象 的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节
2. UML类图
- Product 就是所需要创建的产品
- Builder 创建一个Poroduct对象的各个部分的指定的 接口/抽象类
- ConcreteBuilder 具体的一个创建者,实现Builder中的各个方法,完成各个部分建造的具体实现
- Director 建造的指挥者,内含有一个Builder接口,既然是指挥者,作用就是指挥Builder接口按照自己设定的流程安排每一个部分应该怎么执行,然后得到Builder创建的对象并交给客户端。所以指挥者还有一个作用是隔离客户和产品的生产过程
3. 实例
使用建造者模式呈现一个房子(包含地基、墙体、天花板)的建造过程
我们分UML类图中的四个部分来查看
3.1 Product -- House类
public class House {
private String basic;
private String wall;
private String roof;
constructor...getter...setter...toString...
}
House类或者说产品类,只需要含有产品所需的属性即可
3.2 Builder -- HouseBuilder类
这是一个抽象类,含有一个产品的对象,和建造产品各个属性的对应的方法,这里有三个方法来分别建造房子的三个部分,然后buildHouse方法是将建造好的房子返回
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;
}
}
建造各个部分的方法都是抽象方法,交给子类去实现;而buildHouse()的方法直接将产品对象返回
3.3 ConcreteBuilder -- CommonHouseBuilder类
该类是Builder抽象类/接口的具体实现类,实现了创建各个部分的方法具体的实现过程
public class CommonHouseBuilder extends HouseBuilder {
@Override
public void buildBasic() {
super.house.setBasic("普通房子打地基10米");
}
@Override
public void buildWalls() {
super.house.setWall("普通房子砌粉墙");
}
@Override
public void roofed() {
super.house.setRoof("普通房子的天花板是砖块");
}
}
注意这里构造的对象的父类也就是抽象Builder类中的那个产品对象,所以都使用的是super.house
3.4 Director -- HouseDirector类
指挥类含有一个Builder接口,指挥其按照设定的步骤创建各个部分
public class HouseDirector {
// 使用的是抽象类,运用多态
private HouseBuilder houseBuilder;
public HouseDirector() {
}
public HouseDirector(HouseBuilder houseBuilder) {
this.houseBuilder = houseBuilder;
}
public HouseBuilder getHouseBuilder() {
return houseBuilder;
}
public void setHouseBuilder(HouseBuilder houseBuilder) {
this.houseBuilder = houseBuilder;
}
// 如何处理建造房子的流程,交给指挥者
// 也就是指挥者只会builder将各个部分按照自定义的流程创建然后返回创建好的产品
public House buildHouse() {
// 使用建造者的创建流程
houseBuilder.buildBasic();
houseBuilder.buildWalls();
houseBuilder.roofed();
// 然后返回建造者创建好的对象
return houseBuilder.buildHouse();
}
}
需要设置具体的HouseBuilder的类型,才能够知道要指挥的是建造什么房子的创建者
3.5 使用
public class Client {
public static void main(String[] args) {
// 使用普通房的HouseBuilder来建造房子
System.out.println(new HouseDirector(new CommonHouseBuilder()).buildHouse());
}
}
如果需要增加一种房子,比如增加别墅,由于房子都离不开那三种元素,所以我们只需要增加一个别墅的Builder,继承HouseBuilder,然后实现其中建造各个部分的代码即可。需要建造别墅,就将别墅的Builder对象传入Director,就能够建造别墅了!
4. 总结
- 客户端(使用程序)不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象
- 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象
- 可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程
- 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合 “开闭原则”