建造者模式(Builder)
建造者模式是一种创建型设计模式,它将复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。建造者模式适用于创建具有多个组成部分的复杂对象。
模式定义
建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
核心要点
- 分离构建与表示:构建过程与最终表示分离
- 分步创建:通过多个步骤创建复杂对象
- 控制创建过程:可以精确控制对象的创建过程
- 相同过程不同结果:相同的构建过程可以产生不同的表示
问题场景
假设我们需要创建一个复杂的计算机配置对象,包含多个可选组件:
// 问题代码:构造方法参数过多
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() 中验证 | 在构造方法中验证 |
| 不可变对象 | 容易实现 | 需要多个构造方法 |
优缺点分析
优点
- 分步创建:可以分步创建复杂对象
- 参数命名:参数有明确的名称,代码可读性好
- 可选参数:容易处理可选参数
- 不可变对象:容易创建不可变对象
- 验证集中:可以在 build() 方法中集中验证
缺点
- 增加代码量:需要创建 Builder 类
- 创建开销:需要先创建 Builder 对象
- 设计复杂:对于简单对象可能过度设计
使用建议
何时使用建造者模式
- 对象有很多参数(超过4个)
- 有很多可选参数
- 参数有复杂的验证逻辑
- 需要创建不可变对象
- 构建过程需要多个步骤
何时避免使用建造者模式
- 对象简单,参数少
- 所有参数都是必需的
- 不需要验证参数
最佳实践
- 使用内部 Builder 类:将 Builder 作为产品的静态内部类
- 必需参数放在 Builder 构造方法中:确保必需参数被设置
- 可选参数提供默认值:在 Builder 中设置合理的默认值
- 链式调用:每个设置方法返回 Builder
- 在 build() 中验证:集中验证所有参数
小结
建造者模式是创建复杂对象的利器:
| 应用场景 | 示例 |
|---|---|
| 多参数对象 | User、Computer |
| 不可变对象 | String、LocalDate |
| 配置对象 | Request、Response |
| 构建过程复杂 | House、Meal |
练习
- 实现一个 Pizza 建造者,支持多种配料组合
- 实现一个 SQL 查询建造者,支持 SELECT、WHERE、ORDER BY 等
- 使用 Lombok @Builder 注解简化建造者模式
- 实现一个带参数验证的 Account 建造者