1 概述
前面我们说了工厂模式和抽象工厂模式,下面来说说建造者模式(Builder Pattern)。
建造者模式也是一种极为常见的创建型模式,前面提到的两类工厂模式隐藏了类的属性与构造细节,而建造者模式通过Builder
类,适当地暴露了类的属性,使得类的创建更具有灵活性和可读性。
2 建造者模式
当一个类的构造函数包含很多参数,或者参数之间有很多种组合(如肯德基的套餐),调用构造函数来创建类将会变得不方便,可读性也很差。对于多种组合的情况,工厂模式也将变得不适用。 在这种情况下,建造者模式提供了一种思路,通过将类的创建委托给建造器(Builder),将类的创建与表示分离,大大地简化了类创建的复杂度。
3 案例
考虑做一个Pizza
,为方便起见,让它只包含尺寸,底,馅以及是否加芝士四个属性。看看如何用建造者模式来创建:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public class Test {
public static void main(String[] args) {
Pizza.Builder pizzaBuilder = new Pizza.Builder();
Pizza pizza = pizzaBuilder.size(6)
.crustType(Pizza.CrustType.THIN)
.topping("Durian")
.build();
pizza.info();
}
}
public class Pizza {
private int size;// inch
private CrustType crustType;
private String topping;
private boolean cheese;// optional
private Pizza(Builder builder) {
if (builder.size <= 0) {
throw new IllegalStateException("Invalid pizza size.");
}
if (builder.crustType == null) {
throw new IllegalStateException("Invalid pizza crust type.");
}
if (builder.topping == null) {
throw new IllegalStateException("Invalid pizza topping.");
}
this.size = builder.size;
this.crustType = builder.crustType;
this.topping = builder.topping;
this.cheese = builder.cheese;
}
public void info() {
System.out.println("Pizza size: " + size + ", crust type: " + crustType + ", topping: " + topping + ", with cheese: " + cheese);
}
public static enum CrustType {
THIN, THICK
}
// inner class to build Pizza
public static class Builder {
private int size;
private CrustType crustType;
private String topping;
private boolean cheese = false;
public Builder size(int size) {
this.size = size;
return this;
}
public Builder crustType(CrustType crustType) {
this.crustType = crustType;
return this;
}
public Builder topping(String topping) {
this.topping = topping;
return this;
}
public Builder cheese(boolean cheese) {
this.cheese = cheese;
return this;
}
public Pizza build() {
return new Pizza(this);
}
}
}
输出:
1
Pizza size: 6, crust type: THIN, topping: Durian, with cheese: false
UML:
首先,将类的构造函数私有化了,创建类只能通过Pizza.Builder
来进行。而Pizza.Builder
创建类的过程,其实是一个定制化类,逐步给类设置属性的过程。通过链式调用,可以很容易并直观地给类添加需要的属性,可伸缩性很强。想要创建什么类型的Pizza
,完全由调用者来决定。
建造者模式非常的常见,
如Calendar.Builder,提供了一种自定义构造Calendar
的方式。
如StringBuilder,可以动态,灵活地构造String
对象。类似地还有MyBatis
的AbstractSQL,用直观的方式,逐步地构造一个完整的SQL
语句。
4 总结
当某个类有很多个属性,或者属性之间有多种组合(Calendar.Builder
),又或者是对象维护了一个状态,需要逐步地调用方法使得该状态变得完整(StringBuilder
),请考虑使用建造者模式。