建造者模式 (Builder Pattern)
分步骤构建复杂对象,使构建过程更加灵活清晰
目录
概述
建造者模式是一种创建型设计模式,它允许你分步骤创建复杂对象。该模式使你能够使用相同的创建代码生成不同类型和形式的对象。
适用场景
- 对象构造复杂,参数众多
- 需要创建不同表示的同类对象
- 构造过程需要分步骤执行
基础实现
代码示例
// 产品类
public class Computer {
private String cpu;
private String ram;
private String storage;
private String gpu;
private boolean hasWifi;
private boolean hasBluetooth;
// 私有构造方法
private Computer(Builder builder) {
this.cpu = builder.cpu;
this.ram = builder.ram;
this.storage = builder.storage;
this.gpu = builder.gpu;
this.hasWifi = builder.hasWifi;
this.hasBluetooth = builder.hasBluetooth;
}
// Getters...
// 建造者类
public static class Builder {
private String cpu;
private String ram;
private String storage;
private String gpu;
private boolean hasWifi;
private boolean hasBluetooth;
public Builder cpu(String cpu) {
this.cpu = cpu;
return this;
}
public Builder ram(String ram) {
this.ram = ram;
return this;
}
public Builder storage(String storage) {
this.storage = storage;
return this;
}
public Builder gpu(String gpu) {
this.gpu = gpu;
return this;
}
public Builder hasWifi(boolean hasWifi) {
this.hasWifi = hasWifi;
return this;
}
public Builder hasBluetooth(boolean hasBluetooth) {
this.hasBluetooth = hasBluetooth;
return this;
}
public Computer build() {
return new Computer(this);
}
}
}
// 使用
Computer computer = new Computer.Builder()
.cpu("Intel i9")
.ram("32GB")
.storage("1TB SSD")
.gpu("RTX 4090")
.hasWifi(true)
.hasBluetooth(true)
.build();使用 Lombok 简化
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class User {
private Long id;
private String username;
private String email;
private String phone;
private Integer age;
private String address;
}
// 使用
User user = User.builder()
.id(1L)
.username("john")
.email("john@example.com")
.age(25)
.build();带校验的建造者
public class User {
private final String username;
private final String email;
private final Integer age;
private User(Builder builder) {
this.username = builder.username;
this.email = builder.email;
this.age = builder.age;
}
public static class Builder {
private String username;
private String email;
private Integer age;
public Builder username(String username) {
this.username = username;
return this;
}
public Builder email(String email) {
this.email = email;
return this;
}
public Builder age(Integer age) {
this.age = age;
return this;
}
public User build() {
validate();
return new User(this);
}
private void validate() {
if (username == null || username.isEmpty()) {
throw new IllegalStateException("用户名不能为空");
}
if (email == null || !email.contains("@")) {
throw new IllegalStateException("邮箱格式不正确");
}
if (age == null || age < 0 || age > 150) {
throw new IllegalStateException("年龄不合法");
}
}
}
}框架中的应用
StringBuilder
// JDK 中的建造者模式
String result = new StringBuilder()
.append("Hello")
.append(" ")
.append("World")
.toString();Stream.Builder
// Stream API 中的建造者
Stream<String> stream = Stream.<String>builder()
.add("a")
.add("b")
.add("c")
.build();Spring ResponseEntity
// Spring 的 ResponseEntity 建造者
ResponseEntity<User> response = ResponseEntity
.status(HttpStatus.OK)
.header("X-Custom-Header", "value")
.body(user);Retrofit/OkHttp Request
// OkHttp 的请求建造者
Request request = new Request.Builder()
.url("https://api.example.com/users")
.header("Authorization", "Bearer token")
.get()
.build();实际应用:SQL 查询构造器
public class SqlQuery {
private String select;
private String from;
private String where;
private String orderBy;
private Integer limit;
private SqlQuery(Builder builder) {
this.select = builder.select;
this.from = builder.from;
this.where = builder.where;
this.orderBy = builder.orderBy;
this.limit = builder.limit;
}
public String toSql() {
StringBuilder sql = new StringBuilder();
sql.append("SELECT ").append(select)
.append(" FROM ").append(from);
if (where != null) {
sql.append(" WHERE ").append(where);
}
if (orderBy != null) {
sql.append(" ORDER BY ").append(orderBy);
}
if (limit != null) {
sql.append(" LIMIT ").append(limit);
}
return sql.toString();
}
public static class Builder {
private String select = "*";
private String from;
private String where;
private String orderBy;
private Integer limit;
public Builder select(String... columns) {
this.select = String.join(", ", columns);
return this;
}
public Builder from(String table) {
this.from = table;
return this;
}
public Builder where(String condition) {
this.where = condition;
return this;
}
public Builder orderBy(String column) {
this.orderBy = column;
return this;
}
public Builder limit(int limit) {
this.limit = limit;
return this;
}
public SqlQuery build() {
if (from == null) {
throw new IllegalStateException("FROM 不能为空");
}
return new SqlQuery(this);
}
}
}
// 使用
SqlQuery query = new SqlQuery.Builder()
.select("id", "username", "email")
.from("users")
.where("age > 18")
.orderBy("created_at DESC")
.limit(10)
.build();
System.out.println(query.toSql());
// SELECT id, username, email FROM users WHERE age > 18
// ORDER BY created_at DESC LIMIT 10链式调用 vs 多参数构造
| 方式 | 代码示例 | 可读性 |
|---|---|---|
| 多参数构造 | new User("john", "john@e.com", 25, ...) | 差 |
| Setter | 多行 set 调用 | 一般 |
| 建造者 | .username("john").email("...") | 好 |
优缺点
| 优点 | 缺点 |
|---|---|
| 代码可读性强 | 需要额外创建 Builder 类 |
| 参数清晰明确 | 代码量增加 |
| 支持默认值 | 不适用于简单对象 |
| 可分步构造 | |
| 线程安全(不可变对象) |
最佳实践
- 参数较多时使用:通常超过 4-5 个参数建议使用
- 结合 Lombok:减少样板代码
- 添加参数校验:在 build() 方法中校验
- 创建不可变对象:适合建造者模式