建造者模式
建造者模式用于一步一步构建复杂对象,并把构建过程和对象本身分离。
它特别适合构造参数很多、参数可选、对象创建步骤有顺序要求的场景。
解决什么问题
如果一个类构造参数很多,直接使用构造方法会很难读:
java
OrderQuery query = new OrderQuery(1L, "PAID", null, 1, 20, true, false);调用方很难知道每个参数是什么意思,也容易传错顺序。
建造者模式可以让对象创建变成链式表达:
java
OrderQuery query = OrderQuery.builder()
.userId(1L)
.status("PAID")
.pageNo(1)
.pageSize(20)
.includeItems(true)
.build();基本结构
text
Product:最终要创建的复杂对象
Builder:负责一步一步收集参数
build():校验参数并创建 Product传统 GoF 版本里还有 Director 指挥者,用来固定构建流程。实际 Java 业务开发中,更多使用链式 Builder。
Java 示例
java
public class OrderQuery {
private final Long userId;
private final String status;
private final int pageNo;
private final int pageSize;
private final boolean includeItems;
private OrderQuery(Builder builder) {
this.userId = builder.userId;
this.status = builder.status;
this.pageNo = builder.pageNo;
this.pageSize = builder.pageSize;
this.includeItems = builder.includeItems;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private Long userId;
private String status;
private int pageNo = 1;
private int pageSize = 20;
private boolean includeItems;
public Builder userId(Long userId) {
this.userId = userId;
return this;
}
public Builder status(String status) {
this.status = status;
return this;
}
public Builder pageNo(int pageNo) {
this.pageNo = pageNo;
return this;
}
public Builder pageSize(int pageSize) {
this.pageSize = pageSize;
return this;
}
public Builder includeItems(boolean includeItems) {
this.includeItems = includeItems;
return this;
}
public OrderQuery build() {
if (pageNo <= 0) {
throw new IllegalArgumentException("pageNo must be greater than 0");
}
if (pageSize <= 0 || pageSize > 100) {
throw new IllegalArgumentException("pageSize must be between 1 and 100");
}
return new OrderQuery(this);
}
}
}使用场景
- 查询条件对象。
- HTTP 请求参数对象。
- 配置对象。
- 构造参数很多的 DTO、VO、Command。
- 对象创建前需要做统一校验。
优点
- 调用代码可读性好。
- 可选参数不用写大量重载构造方法。
- 可以在
build()中集中校验。 - 对象可以设计成不可变,线程安全性更好。
缺点
- 会增加 Builder 类。
- 简单对象没必要使用。
- 如果字段很多但没有校验和语义,可能只是把臃肿换了个地方。
和工厂模式的区别
| 模式 | 关注点 |
|---|---|
| 工厂模式 | 创建哪一种对象 |
| 建造者模式 | 一个复杂对象如何一步步构建 |
如果只是根据类型选择实现,用工厂。如果是同一个对象参数复杂,用建造者。
实战注意
现在很多项目会用 Lombok:
java
@Builder
public class OrderQuery {
private Long userId;
private String status;
private Integer pageNo;
private Integer pageSize;
}Lombok 可以减少模板代码,但业务校验仍然要认真设计,不能只为了链式调用而滥用 Builder。