8 建造者模式
8.1 建造者模式概述
Builder Pattern:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式可以将部件本身和它们的组装过程分开,关注如何一步一步地创建一个包含多个组成部分的复杂对象,用户只需指定复杂对象的类型即可得到该对象,而无须知道其内部的具体构造细节。
建造者模式结构图如下:
8.2 建造者模式实现
8.2.1 抽象建造者类
public abstract class Builder {
protected Product product = new Product();
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
// 返回产品对象
public Product getProduct() {
return product;
}
}
8.2.2 具体建造者类
public class ConcreteBuilder extends Builder {
public void buildPartA(PartA partA) {
product.setPartA(partA);
}
public void buildPartB(PartB partB) {
product.setPartB(partB);
}
public void buildPartC(PartC partC) {
product.setPartB(partC);
}
}
8.2.3 具体产品类
public class Product {
private PartA partA;
private PartB partB;
private PartC partC;
/**
* get and set methods
*/
}
8.2.4 指挥者类
引入该类主要有两个作用:
- 隔离了客户端与创建过程
- 控制产品对象的创建过程
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public void setBuilder(Builder builder) {
this.builder = builder;
}
public Product construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
return builder.getProduct();
}
}
8.2.5 客户端调用
对于客户端而言,只需要关注具体建造者的类型,无须关心产品对象的具体创建过程。
public class Client {
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
Product product = director.construct();
}
8.3 指挥者类的变化形式
指挥者类是建造者模式的重要组成部分,简单的 Director 类用于指导具体创建如何创建产品,它按一定顺序调用 Builder 中的各个方法,控制先后顺序,并向客户端返回一个完整的产品对象。
8.3.1 省略指挥者类
为了简化系统结构,某些情况下可以将指挥者类和抽象建造者类进行合并,在 Builder 中提供构建复杂产品对象的 construct() 方法。由于 Builder 通常为抽象类,无法直接实例化,因此可以将 construct() 方法定义为静态方法,以便客户端可以直接调用。
public abstract class Builder {
protected static Product product = new Product();
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
// 返回产品对象
public static Product construct(Builder builder) {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
return product;
}
}
// 客户端调用
public class Client {
Builder builder = new ConcreteBuilder();
Product product = Builder.construct(builder);
}
由于静态变量是被所有实例所共享的,在内存中只有一个副本,因此上述方法只能创建一个 Product 对象。可以做如下改进:
public abstract class Builder {
protected Product product = new Product();
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
// 返回产品对象
public Product construct() {
this.buildPartA();
this.buildPartB();
this.buildPartC();
return product;
}
}
// 客户端调用
Builder builder = new ConcreteBuilder();
Product product = builder.construct();
以上两种方法对 Director 类的省略方式都不影响系统的灵活性和扩展性,同时还简化了系统结构,但是加重了抽象建造者类的职责。如果 construct() 方法较为复杂,待构建产品组成较多,还是应该不省略指挥者类。
8.3.2 钩子方法
建造者模式可以通过 Director 类更加精细的控制产品的创建过程,例如增加一类钩子方法来控制是需要对某个 buildPartX() 方法进行调用。
public abstract class Builder {
protected Product product = new Product();
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
// 钩子方法, 子类可以覆盖该方法
public boolean isBuildPartA() {
return false;
}
public Product construct() {
return product;
}
}
public class Director {
public Product construct(Builder builder) {
if (builder.isBuildPartA()) {
builder.buildPartA();
}
builder.buildPartB();
builder.buildPartC();
Product product = builder.construct();
return product;
}
}
8.4 建造者模式优/缺点
建造者模式优点主要如下:
- 客户端无须知道产品内存的创建细节,将产品本身与创建过程解耦,使得相同的创建过程可以创建不同的产品对象
- 每一个具体的建造者都相对独立,与其他具体建造者无关,可以很方便的增加或删除具体建造者
- 更加精细地控制产品的创建过程,将复杂产品的创建步骤分解在不同的方法中
建造者模式缺点主要如下:
- 如果产品的内部变化复杂,可能会导致需要定义很多具体的建造者类来实现这种变化,导致系统很庞大