这是一个非常常用且重要的设计模式,主要用于解决构造函数参数过多或配置对象复杂的问题。

为什么需要 Builder 模式?(问题背景)
想象一下,你要创建一个 Computer 对象,它有很多可选的配置项:
public class Computer {
private String cpu; // 必需
private String ram; // 必需
private int storage; // 可选
private String gpu; // 可选
private boolean hasMouse; // 可选
private boolean hasKeyboard; // 可选
// 问题来了:如何构造这个对象?
// 方案一:使用重载构造函数
public Computer(String cpu, String ram) { ... }
public Computer(String cpu, String ram, int storage) { ... }
public Computer(String cpu, String ram, int storage, String gpu) { ... }
// ... 无穷无尽的组合,不现实,且代码冗余。
// 方案二:使用“巨型”构造函数,所有参数都设为可选(用默认值)
public Computer(String cpu, String ram, int storage, String gpu, boolean hasMouse, boolean hasKeyboard) {
this.cpu = cpu;
this.ram = ram;
this.storage = storage;
this.gpu = gpu;
this.hasMouse = hasMouse;
this.hasKeyboard = hasKeyboard;
}
}
使用“巨型”构造函数的客户端代码会是这样:
// 糟糕的可读性!你不知道第三个参数是 storage 还是 gpu
Computer gamingPC = new Computer("Intel i9", "32GB", 1000, "NVIDIA RTX 4090", true, true);
这就是著名的 “构造器参数爆炸” 和 “参数不可读” 问题,Builder 模式就是为了优雅地解决这些问题而生的。
Builder 模式的核心思想
Builder 模式的核心思想是:将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。

它包含以下几个角色:
Product(产品类):最终要构建的复杂对象。Computer。Builder(抽象构建器):定义创建产品各个部件的抽象接口。ComputerBuilder。ConcreteBuilder(具体构建器):实现Builder接口,构建和装配产品的各个部件,并返回最终产品。GamingComputerBuilder。Director(指挥者):使用Builder接口来构建产品,它不关心具体的构建细节,只负责按一定流程调用Builder的方法,在某些简化实现中,Director可以被省略,由客户端直接使用Builder。
经典实现(带 Director)
我们先来看一个完整的、包含所有角色的经典实现。
1 1. Product (产品类) - Computer.java
这个类通常会将构造函数设为 private,以防止客户端直接通过 new 来创建实例,同时提供一个静态的 builder() 方法,返回一个 Builder 实例。
public class Computer {
// 1. 所有字段设为 private final,保证对象不可变(Immutable),这是 Builder 模式的最佳实践
private final String cpu;
private final String ram;
private final int storage;
private final String gpu;
private final boolean hasMouse;
private final boolean hasKeyboard;
// 2. 私有构造函数,只能通过 Builder 来创建
private Computer(Builder builder) {
this.cpu = builder.cpu;
this.ram = builder.ram;
this.storage = builder.storage;
this.gpu = builder.gpu;
this.hasMouse = builder.hasMouse;
this.hasKeyboard = builder.hasKeyboard;
}
// 3. 提供一个静态的 builder() 方法,返回构建器实例
public static Builder builder() {
return new Builder();
}
// Getters...
public String getCpu() { return cpu; }
public String getRam() { return ram; }
// ... 其他 getters
// 4. 在 Product 类内部定义 Builder 静态内部类
public static class Builder {
// 5. Builder 的字段与 Product 的字段一一对应
private String cpu;
private String ram;
private int storage = 0; // 可选参数提供默认值
private String gpu;
private boolean hasMouse = false;
private boolean hasKeyboard = false;
// 6. 私有构造函数,通过外部类的 builder() 方法来实例化
private Builder() {}
// 7. 为每个可选参数提供 setter 方法,并返回 this(链式调用)
public Builder cpu(String cpu) {
this.cpu = cpu;
return this;
}
public Builder ram(String ram) {
this.ram = ram;
return this;
}
public Builder storage(int storage) {
this.storage = storage;
return this;
}
public Builder gpu(String gpu) {
this.gpu = gpu;
return this;
}
public Builder hasMouse(boolean hasMouse) {
this.hasMouse = hasMouse;
return this;
}
public Builder hasKeyboard(boolean hasKeyboard) {
this.hasKeyboard = hasKeyboard;
return this;
}
// 8. 提供 build() 方法,用于最终创建并返回 Product 实例
public Computer build() {
// 可以在这里进行参数校验
if (cpu == null || ram == null) {
throw new IllegalStateException("CPU and RAM are required!");
}
return new Computer(this);
}
}
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", ram='" + ram + '\'' +
", storage=" + storage +
", gpu='" + gpu + '\'' +
", hasMouse=" + hasMouse +
", hasKeyboard=" + hasKeyboard +
'}';
}
}
2 2. Director (指挥者) - ComputerDirector.java
Director 负责定义一个固定的构建流程。
public class ComputerDirector {
public Computer constructGamingComputer(Computer.Builder builder) {
return builder
.cpu("Intel i9")
.ram("32GB")
.storage(1000)
.gpu("NVIDIA RTX 4090")
.hasMouse(true)
.hasKeyboard(true)
.build();
}
public Computer constructOfficeComputer(Computer.Builder builder) {
return builder
.cpu("Intel i5")
.ram("16GB")
.storage(512)
.gpu("Integrated Graphics")
.build(); // 其他可选参数使用默认值
}
}
3 3. 客户端使用
public class Client {
public static void main(String[] args) {
// --- 方式一:直接使用 Builder(更常用,更灵活) ---
System.out.println("--- 直接使用 Builder ---");
Computer myPC = Computer.builder()
.cpu("AMD Ryzen 7")
.ram("16GB")
.storage(512)
.gpu("AMD Radeon RX 6700 XT")
.build();
System.out.println(myPC);
// --- 方式二:使用 Director(适用于固定配置模板) ---
System.out.println("\n--- 使用 Director ---");
ComputerDirector director = new ComputerDirector();
Computer gamingPC = director.constructGamingComputer(Computer.builder());
System.out.println(gamingPC);
Computer officePC = director.constructOfficeComputer(Computer.builder());
System.out.println(officePC);
}
}
输出:
--- 直接使用 Builder ---
Computer{cpu='AMD Ryzen 7', ram='16GB', storage=512, gpu='AMD Radeon RX 6700 XT', hasMouse=false, hasKeyboard=false}
--- 使用 Director ---
Computer{cpu='Intel i9', ram='32GB', storage=1000, gpu='NVIDIA RTX 4090', hasMouse=true, hasKeyboard=true}
Computer{cpu='Intel i5', ram='16GB', storage=512, gpu='Integrated Graphics', hasMouse=false, hasKeyboard=false}
简化实现(无 Director,最常用)
在现代开发中,Director 角色用得相对较少,因为它的功能很容易被客户端直接调用 Builder 的链式方法所取代,我们通常只关注 Product 和 Builder。
上面的 Computer 类的实现就是最常用的简化版,它的优点非常突出:
- 可读性高:
Computer.builder().cpu(...).ram(...)这种方式清晰明了,就像在描述如何配置一台电脑。 - 参数灵活:可以自由选择哪些参数需要设置,哪些使用默认值。
- 对象不可变:由于所有字段都是
final,一旦build()完成对象就不可变,这是线程安全和健壮性的保证。 - 参数校验:可以在
build()方法中集中检查参数的有效性。
Builder 模式的优缺点
优点
- 解决了构造函数参数过多的问题。
- 提高了代码的可读性,避免了“参数顺序”和“参数含义”的混淆。
- 支持参数的默认值,客户端无需为每个可选参数都传值。
- 对象不可变性:可以轻松创建不可变对象,这是 Java 并发编程的最佳实践之一。
- 灵活的构造过程:可以在
build()方法中添加校验逻辑,或者在构建器中维护一个状态,确保构建顺序(必须先设置 A 才能设置 B)。
缺点
- 代码量增加:需要为每个需要使用 Builder 模式的类都编写一个对应的
Builder内部类,增加了代码的复杂度。 - 创建对象的过程不直观:相比于直接
new一个对象,Builder 模式需要多一步调用builder()和build()的过程。
Java 标准库中的 Builder 模式
Java 自身也大量使用了 Builder 模式,最典型的例子就是 StringBuilder 和 StringBuffer。
// StringBuilder 就是一个经典的 Builder 模式应用
StringBuilder sb = new StringBuilder(); // Builder
sb.append("Hello"); // 设置部件
sb.append(" ");
sb.append("World"); // 设置部件
String result = sb.toString(); // build() 方法,返回最终产品
另一个例子是 java.lang.StringBuffer,它们都遵循 Builder 模式的核心思想:逐步构建一个复杂的字符串,最后一次性生成结果。
在现代 Java 中,java.util.stream.Builder<T> 接口也体现了这种思想。
Lombok 的 @Builder 注解
为了简化 Builder 模式的实现,强大的 Lombok 库提供了 @Builder 注解,它可以通过一个注解自动为我们生成上面手动编写的所有 Builder 相关代码。
使用 Lombok 后,Computer 类可以简化为:
import lombok.Builder;
import lombok.ToString;
@Builder // Lombok 会自动生成一个静态内部类 Builder,并 builder() 和 build() 方法
@ToString // Lombok 自动生成 toString()
public class Computer {
private final String cpu;
private final String ram;
private final int storage;
private final String gpu;
private final boolean hasMouse;
private final boolean hasKeyboard;
}
客户端代码完全不变,但开发者无需再手动编写繁琐的 Builder 类,这是目前在实际项目中非常流行的用法。
| 特性 | 描述 |
|---|---|
| 核心目的 | 解决构造函数参数过多和可读性差的问题。 |
| 关键角色 | Product (产品), Builder (构建器), Director (指挥者,可选)。 |
| 核心优势 | 高可读性、灵活性、支持默认值、易于创建不可变对象。 |
| 经典实现 | 在 Product 类中定义一个静态 Builder 内部类,提供链式 setter 和一个 build() 方法。 |
| 现代实践 | 广泛使用,是构建复杂配置对象的推荐方式,Lombok 的 @Builder 注解极大地简化了其实现。 |
Builder 模式是 Java 开发者工具箱中一个不可或缺的工具,掌握它能让你的代码更加优雅和健壮。
