跳到主要内容

建造者模式(Builder)

建造者模式是一种创建型设计模式,它将复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。建造者模式适用于创建具有多个组成部分的复杂对象。

模式定义

建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

核心要点

  1. 分离构建与表示:构建过程与最终表示分离
  2. 分步创建:通过多个步骤创建复杂对象
  3. 控制创建过程:可以精确控制对象的创建过程
  4. 相同过程不同结果:相同的构建过程可以产生不同的表示

问题场景

假设我们需要创建一个复杂的计算机配置对象,包含多个可选组件:

// 问题代码:构造方法参数过多
public class Computer {
private String cpu;
private String ram;
private String storage;
private String gpu;
private String motherboard;
private String powerSupply;
private String case_;

// 构造方法重载,组合爆炸
public Computer(String cpu, String ram) { ... }
public Computer(String cpu, String ram, String storage) { ... }
public Computer(String cpu, String ram, String storage, String gpu) { ... }
// ... 无数种组合

// 或者使用一个超长构造方法
public Computer(String cpu, String ram, String storage,
String gpu, String motherboard,
String powerSupply, String case_) {
this.cpu = cpu;
this.ram = ram;
// ...
}
}

// 使用时参数顺序容易出错
Computer computer = new Computer(
"Intel i7", // cpu
"16GB", // ram
null, // storage
"RTX 3080", // gpu
null, // motherboard
"750W", // powerSupply
null // case
);

存在的问题

  • 构造方法参数过多,难以使用
  • 参数顺序容易出错
  • 可选参数处理困难
  • 构造方法重载导致代码膨胀

解决方案

使用建造者模式,通过链式调用逐步构建对象:

// 计算机类
public class Computer {
// 必需参数
private final String cpu;
private final String ram;

// 可选参数
private final String storage;
private final String gpu;
private final String motherboard;
private final String powerSupply;
private final String case_;

// 私有构造方法,只能通过 Builder 创建
private Computer(Builder builder) {
this.cpu = builder.cpu;
this.ram = builder.ram;
this.storage = builder.storage;
this.gpu = builder.gpu;
this.motherboard = builder.motherboard;
this.powerSupply = builder.powerSupply;
this.case_ = builder.case_;
}

// 静态内部 Builder 类
public static class Builder {
// 必需参数
private final String cpu;
private final String ram;

// 可选参数(设置默认值)
private String storage = "256GB SSD";
private String gpu = null;
private String motherboard = null;
private String powerSupply = "500W";
private String case_ = "标准机箱";

// Builder 构造方法,包含必需参数
public Builder(String cpu, String ram) {
this.cpu = cpu;
this.ram = ram;
}

// 设置可选参数的方法,返回 Builder 实现链式调用
public Builder storage(String storage) {
this.storage = storage;
return this;
}

public Builder gpu(String gpu) {
this.gpu = gpu;
return this;
}

public Builder motherboard(String motherboard) {
this.motherboard = motherboard;
return this;
}

public Builder powerSupply(String powerSupply) {
this.powerSupply = powerSupply;
return this;
}

public Builder case_(String case_) {
this.case_ = case_;
return this;
}

// 构建 Computer 对象
public Computer build() {
return new Computer(this);
}
}

@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", ram='" + ram + '\'' +
", storage='" + storage + '\'' +
", gpu='" + gpu + '\'' +
", motherboard='" + motherboard + '\'' +
", powerSupply='" + powerSupply + '\'' +
", case_='" + case_ + '\'' +
'}';
}
}

// 使用示例
public class Client {
public static void main(String[] args) {
// 基础配置
Computer basic = new Computer.Builder("Intel i5", "8GB")
.build();
System.out.println(basic);

// 高性能配置
Computer gaming = new Computer.Builder("Intel i9", "32GB")
.storage("1TB NVMe SSD")
.gpu("RTX 4090")
.motherboard("Z790")
.powerSupply("1000W")
.case_("全塔机箱")
.build();
System.out.println(gaming);
}
}

输出

Computer{cpu='Intel i5', ram='8GB', storage='256GB SSD', gpu='null', motherboard='null', powerSupply='500W', case_='标准机箱'}
Computer{cpu='Intel i9', ram='32GB', storage='1TB NVMe SSD', gpu='RTX 4090', motherboard='Z790', powerSupply='1000W', case_='全塔机箱'}

模式结构

组成部分

  • Builder(抽象建造者):定义创建产品各个部件的抽象接口
  • ConcreteBuilder(具体建造者):实现 Builder 接口,构建和装配各个部件
  • Product(产品):被构建的复杂对象
  • Director(指挥者):使用 Builder 接口构建对象

实现方式

1. 经典实现(带指挥者)

// 产品类
public class House {
private String foundation;
private String structure;
private String roof;
private String interior;

// setters and getters
public void setFoundation(String foundation) { this.foundation = foundation; }
public void setStructure(String structure) { this.structure = structure; }
public void setRoof(String roof) { this.roof = roof; }
public void setInterior(String interior) { this.interior = interior; }

@Override
public String toString() {
return "House{" +
"foundation='" + foundation + '\'' +
", structure='" + structure + '\'' +
", roof='" + roof + '\'' +
", interior='" + interior + '\'' +
'}';
}
}

// 抽象建造者
public interface HouseBuilder {
void buildFoundation();
void buildStructure();
void buildRoof();
void buildInterior();
House getResult();
}

// 具体建造者:木屋
public class WoodenHouseBuilder implements HouseBuilder {
private House house = new House();

@Override
public void buildFoundation() {
house.setFoundation("木桩地基");
}

@Override
public void buildStructure() {
house.setStructure("木质结构");
}

@Override
public void buildRoof() {
house.setRoof("木质屋顶");
}

@Override
public void buildInterior() {
house.setInterior("木质内饰");
}

@Override
public House getResult() {
return house;
}
}

// 具体建造者:混凝土房屋
public class ConcreteHouseBuilder implements HouseBuilder {
private House house = new House();

@Override
public void buildFoundation() {
house.setFoundation("混凝土地基");
}

@Override
public void buildStructure() {
house.setStructure("钢筋混凝土结构");
}

@Override
public void buildRoof() {
house.setRoof("瓦片屋顶");
}

@Override
public void buildInterior() {
house.setInterior("现代内饰");
}

@Override
public House getResult() {
return house;
}
}

// 指挥者
public class HouseDirector {
private HouseBuilder builder;

public HouseDirector(HouseBuilder builder) {
this.builder = builder;
}

public void setBuilder(HouseBuilder builder) {
this.builder = builder;
}

// 构建标准房屋
public House constructStandardHouse() {
builder.buildFoundation();
builder.buildStructure();
builder.buildRoof();
builder.buildInterior();
return builder.getResult();
}

// 构建简易房屋(没有内饰)
public House constructSimpleHouse() {
builder.buildFoundation();
builder.buildStructure();
builder.buildRoof();
return builder.getResult();
}
}

// 使用
public class Client {
public static void main(String[] args) {
HouseDirector director = new HouseDirector(new WoodenHouseBuilder());
House woodenHouse = director.constructStandardHouse();
System.out.println("木屋: " + woodenHouse);

director.setBuilder(new ConcreteHouseBuilder());
House concreteHouse = director.constructStandardHouse();
System.out.println("混凝土房屋: " + concreteHouse);
}
}

2. 简化实现(内部 Builder)

// 使用内部 Builder 类(推荐)
public class User {
private final String firstName;
private final String lastName;
private final int age;
private final String email;
private final String phone;
private final String address;

private User(Builder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.age = builder.age;
this.email = builder.email;
this.phone = builder.phone;
this.address = builder.address;
}

public static class Builder {
private final String firstName;
private final String lastName;
private int age = 0;
private String email = "";
private String phone = "";
private String address = "";

public Builder(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

public Builder age(int age) {
this.age = age;
return this;
}

public Builder email(String email) {
this.email = email;
return this;
}

public Builder phone(String phone) {
this.phone = phone;
return this;
}

public Builder address(String address) {
this.address = address;
return this;
}

public User build() {
return new User(this);
}
}

@Override
public String toString() {
return String.format("User{name='%s %s', age=%d, email='%s', phone='%s', address='%s'}",
firstName, lastName, age, email, phone, address);
}
}

// 使用
User user = new User.Builder("张", "三")
.age(25)
.email("[email protected]")
.phone("13800138000")
.build();

3. 带验证的 Builder

public class Account {
private final String username;
private final String password;
private final String email;

private Account(Builder builder) {
this.username = builder.username;
this.password = builder.password;
this.email = builder.email;
}

public static class Builder {
private String username;
private String password;
private String email;

public Builder username(String username) {
this.username = username;
return this;
}

public Builder password(String password) {
this.password = password;
return this;
}

public Builder email(String email) {
this.email = email;
return this;
}

public Account build() {
// 验证必需字段
if (username == null || username.isEmpty()) {
throw new IllegalStateException("用户名不能为空");
}
if (password == null || password.length() < 6) {
throw new IllegalStateException("密码长度至少为6位");
}
if (email == null || !email.contains("@")) {
throw new IllegalStateException("邮箱格式不正确");
}
return new Account(this);
}
}
}

实际应用案例

1. StringBuilder

Java 的 StringBuilder 是建造者模式的应用:

StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" ");
sb.append("World");
String result = sb.toString(); // "Hello World"

2. Lombok @Builder

Lombok 提供的 @Builder 注解自动生成建造者模式代码:

@Builder
public class Person {
private String name;
private int age;
private String email;
}

// 使用
Person person = Person.builder()
.name("张三")
.age(25)
.email("[email protected]")
.build();

3. OkHttp Request

OkHttp 使用建造者模式构建请求:

OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
.url("https://api.example.com/users")
.header("Authorization", "Bearer token")
.post(RequestBody.create(
MediaType.parse("application/json"),
"{\"name\":\"张三\"}"
))
.build();

Response response = client.newCall(request).execute();

4. Spring Security 配置

Spring Security 使用建造者模式配置安全规则:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.defaultSuccessUrl("/home")
.permitAll()
)
.logout(logout -> logout
.logoutSuccessUrl("/login?logout")
.permitAll()
);

return http.build();
}
}

5. AlertDialog (Android)

Android 的 AlertDialog 使用建造者模式:

AlertDialog dialog = new AlertDialog.Builder(context)
.setTitle("确认删除")
.setMessage("确定要删除这个文件吗?")
.setPositiveButton("删除", (d, which) -> {
// 删除操作
})
.setNegativeButton("取消", null)
.setIcon(R.drawable.ic_warning)
.setCancelable(false)
.create();

dialog.show();

建造者模式 vs 工厂模式

特性建造者模式工厂模式
关注点如何构建复杂对象如何创建对象
对象复杂度复杂对象,多个部分简单对象
创建过程分步构建一步创建
返回时机构建完成后返回立即返回

建造者模式 vs 构造方法

特性建造者模式构造方法
参数命名有命名,清晰无命名,按顺序
可选参数容易处理需要重载
参数验证在 build() 中验证在构造方法中验证
不可变对象容易实现需要多个构造方法

优缺点分析

优点

  1. 分步创建:可以分步创建复杂对象
  2. 参数命名:参数有明确的名称,代码可读性好
  3. 可选参数:容易处理可选参数
  4. 不可变对象:容易创建不可变对象
  5. 验证集中:可以在 build() 方法中集中验证

缺点

  1. 增加代码量:需要创建 Builder 类
  2. 创建开销:需要先创建 Builder 对象
  3. 设计复杂:对于简单对象可能过度设计

使用建议

何时使用建造者模式

  • 对象有很多参数(超过4个)
  • 有很多可选参数
  • 参数有复杂的验证逻辑
  • 需要创建不可变对象
  • 构建过程需要多个步骤

何时避免使用建造者模式

  • 对象简单,参数少
  • 所有参数都是必需的
  • 不需要验证参数

最佳实践

  1. 使用内部 Builder 类:将 Builder 作为产品的静态内部类
  2. 必需参数放在 Builder 构造方法中:确保必需参数被设置
  3. 可选参数提供默认值:在 Builder 中设置合理的默认值
  4. 链式调用:每个设置方法返回 Builder
  5. 在 build() 中验证:集中验证所有参数

小结

建造者模式是创建复杂对象的利器:

应用场景示例
多参数对象User、Computer
不可变对象String、LocalDate
配置对象Request、Response
构建过程复杂House、Meal

练习

  1. 实现一个 Pizza 建造者,支持多种配料组合
  2. 实现一个 SQL 查询建造者,支持 SELECT、WHERE、ORDER BY 等
  3. 使用 Lombok @Builder 注解简化建造者模式
  4. 实现一个带参数验证的 Account 建造者

参考资源