这是一个常见的 Builder 模式创建对象的示例:
Person person = Person.builder() // 静态入口
.firstName("John") // 链式调用
.lastName("Doe")
.age(30)
.build(); // 最终构造
当类的字段较多(尤其是可选参数)、构造逻辑复杂,或字段为 final
类型(不可通过 setter
修改)时,直接通过构造方法或 new
+ setter
的方式会变得笨拙。
Builder 模式能:
new Person(a, b, c, d...)
)。假设我们现在有一个场景,需要定义一个 Person
类,并且可以通过 Builder 模式来创建对象。
下面,我们来一步一步实现。
Person
类与对应字段。public class Person {
private final String firstName;
private final String lastName;
private final int age;
public Person(String firstName, String lastName, int age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
public Person() {}
}
上面,我们定义了一个 Person 类与我们最常见的全参和无参构造方法,我们现在可以创建一个 Person 类型对象,但是我们仍然无法实现链式编程。
Builder
及静态方法 builder()
public class Person {
private final String firstName;
private final String lastName;
private final int age;
public static class Builder {
}
// 入口方法:获取 Builder 实例
public static Builder builder() {
return new Builder();
}
}
上面,我们移除了全参和无参构造方法,我们创建了一个静态内部类 Builder 和 静态方法 builder()
,方法返回值为一个 Builder 类型对象。
注意:定义静态方法的原因是我们可以通过 类.方法
的方式去调用一个方法。
现在我们可以通过 Person.builder()
来获取到一个 Builder 类型对象,例如:
Person person = Person.builder();
虽然有内个意思了,但是 person 的属性现在仍然是为空的。
public class Person {
private final String firstName;
private final String lastName;
private final int age;
public static class Builder {
private String firstName;
private String lastName;
private int age;
}
public static Builder builder() {
return new Builder();
}
}
我们为静态内部类 Builder 添加了与 Person 类的同名字段 firstName
、lastName
和 age
。现在我们还是和第二步一样,只能构建出空的 Person 类型的 person 变量,无法为其赋值。
public class Person {
private final String firstName;
private final String lastName;
private final int age;
public static class Builder {
private String firstName;
private String lastName;
private int age;
public Builder firstName(String firstName) {
this.firstName = firstName;
return this;
}
public Builder lastName(String lastName) {
this.lastName = lastName;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
}
public static Builder builder() {
return new Builder();
}
}
我们为静态内部类 Builder 添加了与属性同名的方法 firstName()
、lastName()
、age()
,我们现在可以通过这三个方法为静态内部类 Builder 的属性进行赋值,并且方法返回值为 Builder 类型对象。
示例:
Person person = Person.builder()
.firstName("John")
.lastName("Doe")
.age(30);
解析:我们在调用 Person.builder()
时,会创建一个 Builder 类型对象,由于该类为静态内部类,所以可以直接通过 类.方法
的方式访问方法,那在调用 firstName("John")
方法时,会为 Builder
的 firstName
属性进行赋值并返回一个 Builder 类型对象,因此我们可以继续调用其他方法来进行赋值。
现在可以为 Builder 类型对象赋值,虽然起到了形似的效果,但是还是不能为 person 变量赋值。
public class Person {
private final String firstName;
private final String lastName;
private final int age;
public static class Builder {
private String firstName;
private String lastName;
private int age;
public Builder firstName(String firstName) {
this.firstName = firstName;
return this;
}
public Builder lastName(String lastName) {
this.lastName = lastName;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Person build() {
return new Person(firstName, lastName, age);
}
}
public static Builder builder() {
return new Builder();
}
}
我们添加了一个 build()
方法,该方法会创建一个 Person 类型对象并为其赋值,值即 Builder 中的属性值。
此时我们便可以实现创建一个 Person 类型对象,并为其赋值了。
Person person = Person.builder() // 静态入口
.firstName("John") // 链式调用
.lastName("Doe")
.age(30)
.build(); // 最终构造
上面的流程是,我们声明了一个 Person 类型的 person 变量,然后通过 类.方法
的方式调用了静态方法 builder()
,即 Person.builder()
,该方法会返回一个 Builder 类型的对象,然后继续调用 firstName("John")
为 Builder 类的属性 firstName
赋值为 "John"
,并返回一个 Builder 类型对象,以此类推,最终我们调用 build()
创建一个 Person 类型对象,并将其赋值为 Builder 类的属性的值,并返回。最终 person 变量接收到这个 Person 类型的对象。
new
+ setter
方式特性 | Builder 模式 | new + setter |
---|---|---|
不可变对象 | ✅ 字段为 final |
❌ 需手动保证 |
线程安全 | ✅ 对象创建后不可变 | ❌ 中途状态可能被修改 |
参数校验 | ✅ 可在 build() 统一校验 |
❌ 分散在多个 setter 中 |
多参数构造 | ✅ 无需记忆顺序 | ❌ 构造方法易混淆 |
代码可读性 | ✅ 链式调用清晰明了 | ❌ 冗长的 setter 调用 |
在 build()
方法中确保参数有效:
public Person build() {
if (firstName == null || lastName == null) {
throw new IllegalArgumentException("姓名不能为空!");
}
return new Person(firstName, lastName, age);
}
public static class Builder {
private String firstName = "Anonymous"; // 默认值
// ... 其他字段 ...
}
通过手动实现 Builder 模式,我们能够:
实现 Builder 模式是更可靠的选择。