设计模式篇-建造者模式

引出建造者模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Person {
private final String name;
private final Sex sex;
private final Integer age;
private final Float height;
private final Float weight;
public Person(String name, Sex sex, Integer age, Float height, Float weight) {
this.name = name;
this.sex = sex;
this.age = age;
this.height = height;
this.weight = weight;
}
}
enum Sex {
MALE, FOMALE
}

由于Person的域都是final的,就必须在创建Person实例时,通过构造函数初始化。

1
new Person("tom",Sex.MALE,20,170f,100f)

创建Person实例时,需要提供所需的全部的属性,这就为只想设置部分属性带来了不便。然而还是可以通过重载构造函数或静态构造器实现。

1
2
3
4
5
6
7
8
9
//构造25岁的男人(重载构造函数)
public Person(String name, Float height, Float weight) {
this(name, Sex.MALE, 25, height, weight);
}
//构造25岁的男人(静态构造器)
public static Person ManOf25(String name, Float height, Float weight) {
return new Person(name, Sex.MALE, 25, height, weight);
}

当需要更多种类的人,就需要更多的构造函数或静态构造器,这将导致一个简单的Person类冗长,难以维护。面对大量的构造函数,调用者将无从知晓到底应该调用哪个构造函数,这无疑是噩梦般的存在。

这时你会说,设置Person的域为非final的,通过getter/setter的方式动态调整属性,不就能满足多变的需求。然而在创建类时,尽量要保证类为不可变类,这样在多线程的环境下,更容易保证线程安全性,非final的对象需要更多额外的同步机制才能安全使用。

既要保证类的不可变性,又要使类更加灵活就可以使用建造者模式。

用建造者模式改造

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
public class Person {
private final String name;
private final Sex sex;
private final Integer age;
private final Float height;
private final Float weight;
//Person通过静态内部类Builder构造
public Person(Builder builder) {
this.name = builder.name;
this.sex = builder.sex;
this.age = builder.age;
this.height = builder.height;
this.weight = builder.weight;
}
//静态方法返回Builder实例
public static Builder builder() {
return new Builder();
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", sex=" + sex +
", age=" + age +
", height=" + height +
", weight=" + weight +
'}';
}
public static class Builder {
private String name;
private Sex sex;
private Integer age;
private Float height;
private Float weight;
Builder withName(String name) {
this.name = name;
return this;
}
Builder withSex(Sex sex) {
this.sex = sex;
return this;
}
Builder withAge(Integer age) {
this.age = age;
return this;
}
Builder withHeight(Float height) {
this.height = height;
return this;
}
Builder withWeight(Float weight) {
this.weight = weight;
return this;
}
//属性赋值完成后,调用build方法创建Person实例
public Person build() {
return new Person(this);
}
}
}

此时创建Person实例将更加灵活,代码也更具可读性。

1
2
3
4
5
6
7
Person person = Person.builder()
.withName("gipple")
.withSex(Sex.MALE)
.withAge(25)
.withHeight(170f)
.withWeight(120f)
.build();

小结

什么是建造者模式

将一个复杂对象的构建与它的属性分离,使的同样的构建过程可以创建具有不同属性的实例。

优点

  1. 使用链式赋值创建实例更优雅。
  2. 类是不可变的,更容易在多线程中使用。

缺点

  1. 需要创建Builder,代码结构较复杂,维护不易。

适用场景

类的属性较多,需要更灵活的组装类时。

实际应用

  1. java.lang.StringBuilder