Builder

想必受过 POJO 中 getter、setter、toString 方法折磨的同学都用过 Lombok,今天我们就一起来探讨一下 Lombok 中是怎样实现 Builder 模式的。

User 类

假设我们存在这样一个 POJO 类,而且客户端在构建 User 对象时并非所有的字段都是必选的。

1
2
3
4
5
6
7
public class User {
private String name;
private int age;
private String phone;
private Address address;
}

1
2
3
4
public class Address {
private String zip;
private String name;
}

不用 Builder 模式

为了满足上述场景,我们需要为 User 类构建如下所示的构造函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public User(String name) {
this(name, 0);
}

public User(String name, int age) {
this(name, age, null);
}

public User(String name, int age, String phone) {
this(name, age, phone, null);
}

public User(String name, int age, String phone, Address address) {
this.name = name;
this.age = age;
this.phone = phone;
this.address = address;
}

不但有着繁杂的构造函数,而且客户端调用时还需要注意传参的顺序。

使用 Builder 模式

通过 Lombok 中 @Builder 注解生成的 User 类。

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
public class User {
private String name;
private int age;
private String phone;
private Address address;

//User 类只需要一个接收全部参数的构造函数即可,剩下的工作交给 UserBuilder 类。
User(String var1, int var2, String var3, Address var4) {
this.name = var1;
this.age = var2;
this.phone = var3;
this.address = var4;
}
//这里之所以将方法定义为 static,是为了方便客户端通过 User.builder() 的调用形式来生成 UserBuilder 对象。
public static User.UserBuilder builder() {
return new User.UserBuilder();
}

public static class UserBuilder {
private String name;
private int age;
private String phone;
private Address address;

UserBuilder() {
}
//通过链式调用避免了 User 中繁杂的构造函数
public User.UserBuilder name(String var1) {
this.name = var1;
return this;
}
public User.UserBuilder age(int var1) {
this.age = var1;
return this;
}
public User.UserBuilder phone(String var1) {
this.phone = var1;
return this;
}
public User.UserBuilder address(Address var1) {
this.address = var1;
return this;
}
//最后通过 build 方法构建出指定的 User 对象,然后返回给客户端。
public User build() {
return new User(this.name, this.age, this.phone, this.address);
}
public String toString() {
return "User.UserBuilder(name=" + this.name + ", age=" + this.age + ", phone=" + this.phone + ", address=" + this.address + ")";
}
}
}

而客户端只需要一行代码就可以生成任意入参的 User 对象,十分方便。

1
User user = User.builder().name("小明").age(13).build();

总结

  • Builder 模式可以避免繁杂的构造函数。
  • Builder 模式可以简洁客户端的代码。

代码

github 地址

引用