建造者模式
问题
什么是建造者模式?什么时候使用?与工厂模式有什么区别?
答案
核心思想
将复杂对象的构造过程分步骤进行,允许用户只通过需要的步骤来构造对象。特别适合参数多、组合方式多的场景。
使用场景
- 构造器参数 > 4 个
- 有多个可选参数
- 参数之间存在约束关系
- 希望对象创建后不可修改(immutable)
经典实现
Builder 模式
public class HttpRequest {
private final String url; // 必填
private final String method; // 必填
private final Map<String, String> headers; // 可选
private final String body; // 可选
private final int timeout; // 可选
private HttpRequest(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = Collections.unmodifiableMap(builder.headers);
this.body = builder.body;
this.timeout = builder.timeout;
}
public static class Builder {
// 必填参数
private final String url;
private final String method;
// 可选参数 - 设默认值
private Map<String, String> headers = new HashMap<>();
private String body;
private int timeout = 5000;
public Builder(String url, String method) {
this.url = url;
this.method = method;
}
public Builder header(String key, String value) {
this.headers.put(key, value);
return this; // 返回 this 支持链式调用
}
public Builder body(String body) {
this.body = body;
return this;
}
public Builder timeout(int timeout) {
this.timeout = timeout;
return this;
}
public HttpRequest build() {
// 校验参数
if (url == null || url.isEmpty()) {
throw new IllegalStateException("URL 不能为空");
}
return new HttpRequest(this);
}
}
}
// 使用:链式调用,清晰易读
HttpRequest request = new HttpRequest.Builder("https://api.example.com", "POST")
.header("Content-Type", "application/json")
.body("{\"name\": \"test\"}")
.timeout(3000)
.build();
Lombok @Builder
实际项目中通常用 Lombok 自动生成 Builder 代码。
Lombok @Builder
@Builder
@Getter
public class UserDTO {
private final String name;
private final String email;
@Builder.Default
private final String role = "USER";
}
// 使用
UserDTO user = UserDTO.builder()
.name("张三")
.email("zhangsan@example.com")
.build();
Java 中的 Builder 应用
| 类 | 说明 |
|---|---|
StringBuilder | 逐步构建字符串 |
Stream.Builder | 构建 Stream |
Locale.Builder | 构建 Locale |
OkHttp Request.Builder | 构建 HTTP 请求 |
Spring UriComponentsBuilder | 构建 URI |
MockMvcRequestBuilders | 构建测试请求 |
常见面试问题
Q1: 建造者模式和工厂模式的区别?
答案:
| 维度 | 工厂模式 | 建造者模式 |
|---|---|---|
| 关注点 | 创建哪种类型的对象 | 如何构造一个复杂对象 |
| 构建过程 | 一步到位 | 分步骤逐步构建 |
| 使用场景 | 多种产品类型 | 一种产品,多种配置 |
Q2: 为什么 Builder 比多参数构造器好?
答案:
// 多参数构造器:参数含义不直观,容易传错位置
new User("张三", "zhangsan@mail.com", 25, "USER", true, null);
// Builder:每个参数都有名字,可读性强
User.builder()
.name("张三")
.email("zhangsan@mail.com")
.age(25)
.build();
优势:可读性好、可选参数灵活、便于校验、对象不可变。