1. 核心定义
建造者模式将一个复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表示。它的核心是 "分步构建 + 统一组装":先按固定步骤拆解对象的构建流程(如造汽车分 "装底盘→装发动机→装座椅→喷漆"),再由专门的 "指挥者" 控制步骤顺序,最终生成完整对象。
简单来说:复杂对象像 "乐高模型",建造者负责 "拼每一块零件",指挥者负责 "按说明书顺序拼",客户端只需 "要最终的模型",无需关心零件怎么拼、顺序是什么。
2. 解决的核心问题
当创建的对象满足以下特征时,传统 new
关键字或工厂模式会变得非常繁琐:
- 属性多且可选 :如创建一个 "用户对象",包含姓名(必选)、年龄(可选)、手机号(可选)、地址(可选)、角色(可选)等 10 + 属性,若用构造函数,需重载多个版本(如
User(name)
、User(name, age)
、User(name, age, phone)
...),代码臃肿; - 构建步骤固定且复杂:如创建 "电脑对象",必须按 "装主板→装 CPU→装内存→装硬盘→装电源" 的顺序,步骤不能乱,且每个步骤有细节逻辑(如装 CPU 需涂硅脂),直接写在构造函数里会导致逻辑混乱、难以维护;
- 需要不同表示:同一构建步骤可生成不同结果(如同样是 "造蛋糕",步骤都是 "打胚→抹奶油→装饰",但装饰步骤可做成 "水果蛋糕" 或 "巧克力蛋糕")。
建造者模式的解决方案:
- 用 "建造者" 封装每个步骤的细节(如
ComputerBuilder
含buildMotherboard()
、buildCPU()
方法); - 用 "指挥者" 控制步骤顺序(如
ComputerDirector
规定 "先装主板,再装 CPU"); - 客户端只需指定 "用哪个建造者",即可获得对应表示的复杂对象。
3. 核心角色(4 个)
建造者模式的结构围绕 "分步构建" 设计,包含 4 个核心角色:
角色名称 | 核心职责 | 示例(以 "电脑组装" 为例) |
---|---|---|
产品(Product) | 被构建的复杂对象,包含多个组成部分 | 类 Computer ,含 motherboard (主板)、cpu (CPU)、memory (内存)等属性 |
抽象建造者(Abstract Builder) | 定义构建产品的所有步骤接口(含 "构建步骤" 和 "返回产品" 方法) | 接口 ComputerBuilder ,含 buildMotherboard() 、buildCPU() 、buildMemory() 、getComputer() 方法 |
具体建造者(Concrete Builder) | 实现抽象建造者,完成每个步骤的具体逻辑,可生成不同表示的产品 | 类 GamingComputerBuilder (游戏电脑建造者,装高性能 CPU)、OfficeComputerBuilder (办公电脑建造者,装入门级 CPU) |
指挥者(Director) | 控制构建流程的步骤顺序,调用具体建造者的步骤方法,不关心步骤细节 | 类 ComputerDirector ,含 constructComputer(ComputerBuilder builder) 方法,规定 "先装主板→再装 CPU→再装内存" |
4. 实现步骤与代码示例(Java)
以 "组装游戏电脑和办公电脑" 为例,完整实现建造者模式:
步骤 1:定义产品(Computer)
复杂对象,包含多个组成部分,提供属性设置和展示方法:
java
// 产品:电脑(包含多个组成部分)
public class Computer {
// 组成部分(属性)
private String motherboard; // 主板
private String cpu; // CPU
private String memory; // 内存
private String hardDisk; // 硬盘
// setter方法(由建造者调用,设置各部分)
public void setMotherboard(String motherboard) {
this.motherboard = motherboard;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public void setMemory(String memory) {
this.memory = memory;
}
public void setHardDisk(String hardDisk) {
this.hardDisk = hardDisk;
}
// 展示电脑配置(产品的使用方法)
public void showConfig() {
System.out.println("电脑配置:");
System.out.println("主板:" + motherboard);
System.out.println("CPU:" + cpu);
System.out.println("内存:" + memory);
System.out.println("硬盘:" + hardDisk);
}
}
步骤 2:定义抽象建造者(ComputerBuilder)
规范所有构建步骤的接口,包含 "分步构建" 和 "返回产品" 两个核心方法:
java
// 抽象建造者:电脑建造者(定义所有构建步骤)
public interface ComputerBuilder {
// 步骤1:装主板
void buildMotherboard();
// 步骤2:装CPU
void buildCPU();
// 步骤3:装内存
void buildMemory();
// 步骤4:装硬盘
void buildHardDisk();
// 返回最终产品(电脑)
Computer getComputer();
}
步骤 3:实现具体建造者(游戏电脑 / 办公电脑)
每个具体建造者对应一种 "产品表示",实现步骤的具体逻辑(如游戏电脑用高性能配件):
java
// 具体建造者1:游戏电脑建造者(高性能配置)
public class GamingComputerBuilder implements ComputerBuilder {
// 持有产品实例(逐步构建)
private Computer computer = new Computer();
@Override
public void buildMotherboard() {
computer.setMotherboard("华硕ROG Z790(游戏级主板)");
}
@Override
public void buildCPU() {
computer.setCpu("英特尔i9-14900K(高性能CPU)");
}
@Override
public void buildMemory() {
computer.setMemory("芝奇DDR5 64GB(高频内存)");
}
@Override
public void buildHardDisk() {
computer.setHardDisk("三星990 Pro 2TB(高速SSD)");
}
@Override
public Computer getComputer() {
return computer; // 返回构建好的游戏电脑
}
}
// 具体建造者2:办公电脑建造者(入门级配置)
public class OfficeComputerBuilder implements ComputerBuilder {
private Computer computer = new Computer();
@Override
public void buildMotherboard() {
computer.setMotherboard("微星H610M(办公级主板)");
}
@Override
public void buildCPU() {
computer.setCpu("英特尔i3-13100(入门级CPU)");
}
@Override
public void buildMemory() {
computer.setMemory("金士顿DDR4 16GB(普通内存)");
}
@Override
public void buildHardDisk() {
computer.setHardDisk("金士顿A400 1TB(普通SSD)");
}
@Override
public Computer getComputer() {
return computer; // 返回构建好的办公电脑
}
}
步骤 4:定义指挥者(ComputerDirector)
控制构建步骤的顺序,调用具体建造者的方法完成组装,屏蔽步骤细节:
java
// 指挥者:电脑组装指挥者(控制步骤顺序)
public class ComputerDirector {
// 核心方法:按固定顺序构建电脑
public Computer constructComputer(ComputerBuilder builder) {
// 步骤顺序:主板 → CPU → 内存 → 硬盘(不能乱,如CPU需装在主板上)
builder.buildMotherboard();
builder.buildCPU();
builder.buildMemory();
builder.buildHardDisk();
return builder.getComputer(); // 返回组装好的电脑
}
}
步骤 5:客户端使用(获取复杂对象)
客户端只需选择 "具体建造者",通过指挥者获取产品,无需关心步骤:
java
public class Client {
public static void main(String[] args) {
// 1. 创建指挥者(负责控制步骤)
ComputerDirector director = new ComputerDirector();
// 2. 构建游戏电脑(选择游戏电脑建造者)
ComputerBuilder gamingBuilder = new GamingComputerBuilder();
Computer gamingComputer = director.constructComputer(gamingBuilder);
System.out.println("=== 游戏电脑配置 ===");
gamingComputer.showConfig();
// 3. 构建办公电脑(切换为办公电脑建造者,其他逻辑不变)
ComputerBuilder officeBuilder = new OfficeComputerBuilder();
Computer officeComputer = director.constructComputer(officeBuilder);
System.out.println("\n=== 办公电脑配置 ===");
officeComputer.showConfig();
}
}
运行结果:
plaintext
=== 游戏电脑配置 ===
电脑配置:
主板:华硕ROG Z790(游戏级主板)
CPU:英特尔i9-14900K(高性能CPU)
内存:芝奇DDR5 64GB(高频内存)
硬盘:三星990 Pro 2TB(高速SSD)
=== 办公电脑配置 ===
电脑配置:
主板:微星H610M(办公级主板)
CPU:英特尔i3-13100(入门级CPU)
内存:金士顿DDR4 16GB(普通内存)
硬盘:金士顿A400 1TB(普通SSD)
5. 简化版:流式建造者(无指挥者)
在实际开发中,若构建步骤无需严格控制顺序(如创建 "用户对象"),可省略 "指挥者",让具体建造者支持链式调用 (流式 API),代码更简洁。这种方式在框架(如 Lombok 的 @Builder
)中广泛使用。
以 "用户对象" 为例,实现简化版流式建造者:
java
// 产品:用户(属性多且可选)
public class User {
private String name; // 必选
private int age; // 可选
private String phone; // 可选
private String address; // 可选
// 私有构造函数(只能由建造者创建)
private User(UserBuilder builder) {
this.name = builder.name;
this.age = builder.age;
this.phone = builder.phone;
this.address = builder.address;
}
// 内部静态建造者(流式调用)
public static class UserBuilder {
// 必选属性(必须在构造函数中传入)
private final String name;
// 可选属性(默认值)
private int age = 0;
private String phone = "";
private String address = "";
// 建造者构造函数(传入必选属性)
public UserBuilder(String name) {
this.name = name;
}
// 链式设置可选属性(返回this,支持流式调用)
public UserBuilder age(int age) {
this.age = age;
return this;
}
public UserBuilder phone(String phone) {
this.phone = phone;
return this;
}
public UserBuilder address(String address) {
this.address = address;
return this;
}
// 构建产品(返回User)
public User build() {
// 可在这里加校验(如name不能为空)
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("用户名不能为空");
}
return new User(this);
}
}
// 展示用户信息
public void showInfo() {
System.out.println("姓名:" + name + ",年龄:" + age + ",手机号:" + phone + ",地址:" + address);
}
}
// 客户端使用(流式调用)
public class Client {
public static void main(String[] args) {
// 链式构建用户(必选属性name在建造者构造函数传入,可选属性按需设置)
User user1 = new User.UserBuilder("张三")
.age(25)
.phone("13800138000")
.address("北京市")
.build();
User user2 = new User.UserBuilder("李四")
.phone("13900139000")
.build(); // 不设置age和address,用默认值
user1.showInfo(); // 姓名:张三,年龄:25,手机号:13800138000,地址:北京市
user2.showInfo(); // 姓名:李四,年龄:0,手机号:13900139000,地址:
}
}
6. 应用场景
建造者模式的核心是 "复杂对象的分步构建",适合以下场景:
- 复杂对象创建:对象包含多个组成部分,且构建步骤固定(如汽车、电脑、手机等硬件;文档、报表等软件对象);
- 属性多且可选:对象有大量可选属性,需避免重载多个构造函数(如用户、订单、配置类,对应简化版流式建造者);
- 需不同表示:同一构建步骤需生成不同结果(如蛋糕(水果 / 巧克力)、文档(PDF/Word))。
经典实战案例:
- JDK 中的
StringBuilder
/StringBuffer
:本质是简化的建造者,append()
方法对应 "分步构建字符串",toString()
对应 "返回最终产品"; - 框架中的对象构建:如 MyBatis 的
SqlSessionFactoryBuilder
、Spring 的BeanDefinitionBuilder
,均通过分步调用方法构建复杂对象; - 工具类生成:如 Lombok 的
@Builder
注解,自动为类生成流式建造者,避免手动编写建造者代码。
7. 优缺点分析
优点 | 缺点 |
---|---|
1. 解耦构建与表示:构建步骤由建造者封装,产品表示由具体建造者决定,客户端无需关心细节;2. 灵活控制构建过程:指挥者可调整步骤顺序,具体建造者可修改步骤逻辑,生成不同产品;3. 便于扩展:新增产品表示只需加 "具体建造者",无需改指挥者和产品(符合开闭原则);4. 校验方便:在 build() 方法中可对属性进行校验(如必选属性非空)。 |
1. 类结构复杂:完整模式需 "产品 + 抽象建造者 + 具体建造者 + 指挥者",类数量多;2. 适用范围有限:仅适合 "复杂对象",若对象简单(如只有 2 个属性),用建造者反而冗余。 |
8. 与工厂方法模式的核心区别
建造者模式和工厂方法模式都属于创建型模式,但关注点完全不同:
对比维度 | 工厂方法模式 | 建造者模式 |
---|---|---|
核心目标 | 解决 "创建哪类对象" 的问题(如创建手机还是平板) | 解决 "如何分步构建复杂对象" 的问题(如手机如何装屏幕、电池) |
关注重点 | 产品的 "类型" | 产品的 "构建过程" |
客户端操作 | 客户端只需选择工厂,直接获取产品 | 客户端需指定建造者,由指挥者控制步骤后获取产品 |
适用场景 | 产品类型固定,创建逻辑简单 | 产品复杂(多组成部分),创建步骤固定 |
简单总结:工厂方法是 "一步到位拿产品",建造者是 "分步操作拼产品" 。