建造者模式:分步构建复杂对象的设计模式
一、模式核心:分离对象构建与表示,支持复杂对象分步创建
在软件开发中,当创建一个复杂对象(如配置对象、组合对象)需要多个步骤(如属性设置、子对象初始化)时,直接通过构造方法创建会导致参数列表冗长、代码可读性差。
建造者模式(Builder Pattern) 将一个复杂对象的构建过程与其表示分离,允许使用相同的构建过程创建不同的表示。核心解决:
- 简化复杂对象创建:通过分步方法(如
setName()
、setAge()
)逐步构建对象,避免一次性传递所有参数。 - 支持链式调用:通过返回建造者自身实例,实现方法链式调用,提升代码流畅性。
- 解耦构建逻辑:将构建逻辑封装在建造者类中,便于扩展不同的构建策略(如普通用户与 VIP 用户的创建流程差异)。
核心思想与 UML 类图
建造者模式包含以下角色:
- 产品类(Product):需要构建的复杂对象,包含多个属性。
- 抽象建造者(Builder):定义构建产品各部分的接口,返回建造者实例(链式调用)。
- 具体建造者(Concrete Builder):实现抽象建造者接口,完成具体属性的设置。
- 指挥者(Director):控制构建流程,调用建造者的方法构建产品(可选角色)。
二、核心实现:用户对象的分步构建
1. 定义产品类(用户)
public class User {
private String name; // 必选属性
private int age; // 可选属性
private String email; // 可选属性
private String address; // 可选属性
// 私有化构造方法,强制通过建造者创建
private User(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.email = builder.email;
this.address = builder.address;
}
// Getter 方法(省略 Setter,保证不可变性)
public String getName() { return name; }
public int getAge() { return age; }
public String getEmail() { return email; }
public String getAddress() { return address; }
// 展示用户信息
public void show() {
System.out.println("用户信息:");
System.out.println("姓名:" + name);
System.out.println("年龄:" + age);
System.out.println("邮箱:" + email);
System.out.println("地址:" + address);
}
}
2. 定义抽象建造者(内部类实现)
public class UserBuilder {
private final String name; // 必选属性(构造方法传入)
private int age; // 可选属性(默认值)
private String email; // 可选属性(默认值 null)
private String address; // 可选属性(默认值 null)
// 构造方法强制设置必选属性
public UserBuilder(String name) {
this.name = name;
}
// 可选属性设置方法,返回建造者自身(链式调用)
public UserBuilder setAge(int age) {
this.age = age;
return this;
}
public UserBuilder setEmail(String email) {
this.email = email;
return this;
}
public UserBuilder setAddress(String address) {
this.address = address;
return this;
}
// 构建产品实例
public User build() {
return new User(this); // 将建造者传递给产品构造方法
}
}
3. 客户端使用建造者模式
public class ClientDemo {
public static void main(String[] args) {
// 构建普通用户(设置部分属性)
User normalUser = new UserBuilder("Alice")
.setAge(25)
.build();
// 构建高级用户(设置全部属性)
User advancedUser = new UserBuilder("Bob")
.setAge(30)
.setEmail("bob@example.com")
.setAddress("123 Main St")
.build();
normalUser.show();
System.out.println("\n------------------------\n");
advancedUser.show();
}
}
输出结果:
用户信息:
姓名:Alice
年龄:25
邮箱:null
地址:null
------------------------
用户信息:
姓名:Bob
年龄:30
邮箱:bob@example.com
地址:123 Main St
三、进阶:使用指挥者控制构建流程
当构建流程固定时,可以通过指挥者类封装构建步骤,客户端无需关心具体细节。
1. 定义指挥者类
public class UserDirector {
private final UserBuilder builder;
public UserDirector(UserBuilder builder) {
this.builder = builder;
}
// 定义默认构建流程(如创建必填属性+年龄的用户)
public User constructBasicUser() {
return builder
.setAge(18) // 默认年龄 18 岁
.build();
}
// 定义高级构建流程(设置全部属性)
public User constructFullUser(String email, String address) {
return builder
.setAge(18)
.setEmail(email)
.setAddress(address)
.build();
}
}
2. 客户端通过指挥者构建对象
public class ClientDemo {
public static void main(String[] args) {
UserBuilder builder = new UserBuilder("Charlie");
UserDirector director = new UserDirector(builder);
// 使用指挥者创建基础用户
User basicUser = director.constructBasicUser();
basicUser.show();
}
}
四、框架与源码中的建造者实践
1. JDK 中的 StringBuilder
StringBuilder
使用建造者模式实现字符串的分步拼接,支持链式调用:
String result = new StringBuilder("Hello")
.append(" ")
.append("World")
.toString(); // 输出 "Hello World"
2. MyBatis 的 SqlSessionFactoryBuilder
MyBatis 通过建造者模式构建 SqlSessionFactory
,允许配置数据源、事务管理器等参数:
SqlSessionFactory factory = new SqlSessionFactoryBuilder()
.build(Resources.getResourceAsStream("mybatis-config.xml"));
3. Android 的 AlertDialog.Builder
Android 中通过建造者模式创建对话框,分步设置标题、内容、按钮等:
new AlertDialog.Builder(context)
.setTitle("提示")
.setMessage("确认操作?")
.setPositiveButton("确定", null)
.create()
.show();
五、避坑指南:正确使用建造者模式的 3 个要点
1. 区分建造者与工厂模式
- 工厂模式:专注于 “创建对象”,不关心构建过程(如
new User("Alice", 25)
)。 - 建造者模式:强调 “分步构建”,支持复杂对象的属性逐个设置(如
setName().setAge()
)。
2. 合理设计必选与可选属性
- 必选属性通过建造者的构造方法强制设置,避免出现不完整的产品实例。
- 可选属性通过公共方法设置,允许客户端按需选择。
3. 考虑线程安全
若建造者用于多线程环境,需对共享的产品属性或建造者实例添加同步控制(如 synchronized
)。
六、总结:何时该用建造者模式?
适用场景 | 核心特征 | 典型案例 |
---|---|---|
复杂对象分步构建 | 对象包含多个属性,需分步骤初始化 | 用户配置、订单详情、XML/JSON 解析 |
链式调用需求 | 需要通过方法链提升代码可读性 | 日志构建、SQL 语句拼接 |
构建流程多样化 | 相同构建步骤可生成不同表示的产品 | 报表生成(HTML/Excel/PDF 格式) |
建造者模式通过将复杂对象的构建过程分解为多个简单步骤,使代码更易读、可维护。下一篇我们将探讨桥接模式,解析如何分离抽象与实现,敬请期待!
扩展思考:建造者模式的变种
- 流式建造者:所有设置方法均返回
this
,形成方法链(如示例中的setAge().setEmail()
)。 - 建造者返回不同产品:一个建造者类支持构建多种相关产品(如用户与管理员对象)。