目录
[1. 核心角色分工](#1. 核心角色分工)
[2. 经典版代码实现(Java)](#2. 经典版代码实现(Java))
[步骤 1:定义产品类(Computer)](#步骤 1:定义产品类(Computer))
[步骤 2:定义抽象建造者(ComputerBuilder)](#步骤 2:定义抽象建造者(ComputerBuilder))
[步骤 3:定义具体建造者(游戏本 / 办公本)](#步骤 3:定义具体建造者(游戏本 / 办公本))
[步骤 4:定义指挥者(ComputerDirector)](#步骤 4:定义指挥者(ComputerDirector))
[步骤 5:客户端使用](#步骤 5:客户端使用)
[1. 什么时候必须用建造者模式?](#1. 什么时候必须用建造者模式?)
[2. 建造者模式的变种](#2. 建造者模式的变种)
[3. Lombok 简化建造者模式](#3. Lombok 简化建造者模式)
[4. 建造者模式的坑](#4. 建造者模式的坑)
[1. 建造者模式 vs 工厂模式](#1. 建造者模式 vs 工厂模式)
[2. 建造者模式 vs 原型模式](#2. 建造者模式 vs 原型模式)
一、建造者模式的核心本质
建造者模式是创建型设计模式的核心成员,它解决的核心痛点是:
- 当一个对象属性多、层级深、可选配置多(比如有 10 个以上属性,部分必填、部分可选),如果用普通构造器会出现 "参数爆炸"(Constructor Telescoping),可读性和可维护性极差;
- 希望把对象的 "构建步骤" 和 "具体配置" 分开,让构建流程标准化,配置个性化;
- 确保对象构建过程中状态一致(避免创建出属性不完整的 "半成品" 对象)。
一句话总结:建造者模式 = 标准化构建流程 + 个性化配置 + 保证对象完整性。
二、建造者模式的完整结构(经典版)
经典建造者模式包含 4 个核心角色,缺一不可,我们用 "组装电脑" 这个更直观的场景来拆解:
1. 核心角色分工
| 角色名称 | 核心职责 | 电脑场景示例 |
|---|---|---|
| 产品(Product) | 最终要构建的复杂对象,由多个部件组成 | Computer(包含 CPU、内存、硬盘、显卡、操作系统等部件) |
| 抽象建造者(Builder) | 定义构建产品的所有步骤(抽象方法),包含 "构建部件" 和 "获取产品" 两类方法 | ComputerBuilder(抽象方法:buildCPU ()、buildMemory ()、buildHardDisk ()、buildGraphics ()、getComputer ()) |
| 具体建造者(ConcreteBuilder) | 实现抽象建造者的方法,完成具体部件的构建(比如 "游戏本建造者" 用高性能 CPU,"办公本建造者" 用低功耗 CPU) | GameComputerBuilder(游戏本)、OfficeComputerBuilder(办公本) |
| 指挥者(Director) | 定义构建的顺序和流程(比如先装 CPU→内存→硬盘→显卡→装系统),调用具体建造者的方法完成构建,隔离用户与构建细节 | ComputerDirector(方法:constructComputer (ComputerBuilder builder)) |
2. 经典版代码实现(Java)
步骤 1:定义产品类(Computer)
java
运行
// 复杂产品:电脑
public class Computer {
// 核心部件(部分必填,部分可选)
private String cpu; // 必填
private String memory; // 必填
private String hardDisk; // 必填
private String graphics; // 可选(办公本可无独立显卡)
private String os; // 必填
// 空构造器(由建造者填充属性)
public Computer() {}
// setter方法(建造者调用)
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 setGraphics(String graphics) {
this.graphics = graphics;
}
public void setOs(String os) {
this.os = os;
}
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", memory='" + memory + '\'' +
", hardDisk='" + hardDisk + '\'' +
", graphics='" + graphics + '\'' +
", os='" + os + '\'' +
'}';
}
}
步骤 2:定义抽象建造者(ComputerBuilder)
java
运行
// 抽象建造者:定义构建电脑的所有步骤
public abstract class ComputerBuilder {
// 持有产品对象(所有具体建造者操作同一个产品实例)
protected Computer computer = new Computer();
// 构建核心部件(抽象方法,由具体建造者实现)
public abstract void buildCPU();
public abstract void buildMemory();
public abstract void buildHardDisk();
public abstract void buildGraphics();
public abstract void buildOS();
// 获取构建完成的产品(通用方法,无需子类重写)
public Computer getComputer() {
return this.computer;
}
}
步骤 3:定义具体建造者(游戏本 / 办公本)
java
运行
// 具体建造者1:游戏本建造者(高性能配置)
public class GameComputerBuilder extends ComputerBuilder {
@Override
public void buildCPU() {
computer.setCpu("Intel i9-14900K(高性能游戏CPU)");
}
@Override
public void buildMemory() {
computer.setMemory("32GB DDR5 6000MHz");
}
@Override
public void buildHardDisk() {
computer.setHardDisk("2TB NVMe PCIe4.0 SSD");
}
@Override
public void buildGraphics() {
computer.setGraphics("NVIDIA RTX 4090 24GB");
}
@Override
public void buildOS() {
computer.setOs("Windows 11 专业版");
}
}
// 具体建造者2:办公本建造者(低功耗、高续航)
public class OfficeComputerBuilder extends ComputerBuilder {
@Override
public void buildCPU() {
computer.setCpu("Intel i5-1340P(低功耗办公CPU)");
}
@Override
public void buildMemory() {
computer.setMemory("16GB DDR4 3200MHz");
}
@Override
public void buildHardDisk() {
computer.setHardDisk("1TB SATA3 SSD");
}
@Override
public void buildGraphics() {
computer.setGraphics("集成显卡(UHD Graphics)");
}
@Override
public void buildOS() {
computer.setOs("Windows 11 家庭版");
}
}
步骤 4:定义指挥者(ComputerDirector)
java
运行
// 指挥者:定义构建流程,隔离用户与构建细节
public class ComputerDirector {
// 构建电脑的核心方法(参数为抽象建造者,符合开闭原则)
public Computer constructComputer(ComputerBuilder builder) {
// 固定构建顺序:CPU → 内存 → 硬盘 → 显卡 → 系统
builder.buildCPU();
builder.buildMemory();
builder.buildHardDisk();
builder.buildGraphics();
builder.buildOS();
// 返回构建完成的产品
return builder.getComputer();
}
}
步骤 5:客户端使用
java
运行
public class Client {
public static void main(String[] args) {
// 1. 创建指挥者(统一管理构建流程)
ComputerDirector director = new ComputerDirector();
// 2. 构建游戏本
ComputerBuilder gameBuilder = new GameComputerBuilder();
Computer gameComputer = director.constructComputer(gameBuilder);
System.out.println("游戏本配置:" + gameComputer);
// 3. 构建办公本
ComputerBuilder officeBuilder = new OfficeComputerBuilder();
Computer officeComputer = director.constructComputer(officeBuilder);
System.out.println("办公本配置:" + officeComputer);
}
}
输出结果
plaintext
游戏本配置:Computer{cpu='Intel i9-14900K(高性能游戏CPU)', memory='32GB DDR5 6000MHz', hardDisk='2TB NVMe PCIe4.0 SSD', graphics='NVIDIA RTX 4090 24GB', os='Windows 11 专业版'}
办公本配置:Computer{cpu='Intel i5-1340P(低功耗办公CPU)', memory='16GB DDR4 3200MHz', hardDisk='1TB SATA3 SSD', graphics='集成显卡(UHD Graphics)', os='Windows 11 家庭版'}
三、建造者模式的简化版(实战常用)
经典版需要创建 4 个类,结构偏复杂,日常开发中更常用 **"静态内部类 + 链式调用"** 的简化版(也叫 "流式建造者"),无需单独的 Director 和抽象 Builder,核心特点:
- 产品类中嵌套静态内部 Builder 类;
- Builder 类提供链式 setter 方法(返回 this);
- Builder 的 build () 方法完成参数校验并创建产品实例;
- 产品类构造器私有化,确保只能通过 Builder 创建。
简化版代码(电脑场景)
java
运行
public class Computer {
// 核心属性(final保证不可变,线程安全)
private final String cpu;
private final String memory;
private final String hardDisk;
private final String graphics;
private final String os;
// 私有化构造器,仅内部Builder调用
private Computer(Builder builder) {
this.cpu = builder.cpu;
this.memory = builder.memory;
this.hardDisk = builder.hardDisk;
this.graphics = builder.graphics;
this.os = builder.os;
}
// 静态内部建造者类
public static class Builder {
// 必填属性(无默认值)
private final String cpu;
private final String memory;
private final String os;
// 可选属性(有默认值)
private String hardDisk = "512GB SATA3 SSD";
private String graphics = "集成显卡";
// Builder构造器:强制传入必填属性
public Builder(String cpu, String memory, String os) {
this.cpu = cpu;
this.memory = memory;
this.os = os;
}
// 链式调用:设置可选属性
public Builder hardDisk(String hardDisk) {
this.hardDisk = hardDisk;
return this;
}
public Builder graphics(String graphics) {
this.graphics = graphics;
return this;
}
// 构建产品:包含参数校验
public Computer build() {
// 校验必填属性(非空、合法)
if (cpu == null || cpu.isEmpty()) {
throw new IllegalArgumentException("CPU不能为空");
}
return new Computer(this);
}
}
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", memory='" + memory + '\'' +
", hardDisk='" + hardDisk + '\'' +
", graphics='" + graphics + '\'' +
", os='" + os + '\'' +
'}';
}
}
客户端使用(链式调用)
java
运行
public class Client {
public static void main(String[] args) {
// 构建游戏本(自定义可选属性)
Computer gameComputer = new Computer.Builder(
"Intel i9-14900K",
"32GB DDR5",
"Windows 11 专业版"
)
.hardDisk("2TB NVMe SSD")
.graphics("RTX 4090")
.build();
// 构建办公本(使用可选属性默认值)
Computer officeComputer = new Computer.Builder(
"Intel i5-1340P",
"16GB DDR4",
"Windows 11 家庭版"
).build();
System.out.println("游戏本:" + gameComputer);
System.out.println("办公本:" + officeComputer);
}
}
四、建造者模式的关键细节
1. 什么时候必须用建造者模式?
- 对象有多个必填属性 + 多个可选属性,且属性之间有依赖关系(比如 "选了独立显卡就必须选高性能电源");
- 需要控制对象的构建顺序(比如必须先初始化基础配置,再配置扩展功能);
- 希望避免创建不完整的对象(比如禁止只设置 CPU 就使用电脑);
- 希望代码可读性高(链式调用比一堆 setter 更直观)。
2. 建造者模式的变种
| 变种类型 | 适用场景 | 示例 |
|---|---|---|
| 经典版(Director + Builder) | 构建流程固定、产品类型多(比如游戏本 / 办公本 / 服务器) | 框架级代码(如 MyBatis 的 SqlSessionFactoryBuilder) |
| 简化版(静态内部 Builder) | 单个产品、配置灵活、无需统一流程 | 业务层复杂对象(如订单、用户、设备) |
| 流式建造者(Fluent Builder) | 追求代码简洁、链式调用 | Lombok 的 @Builder 注解 |
3. Lombok 简化建造者模式
日常开发中可以用 Lombok 的@Builder注解自动生成建造者代码,无需手写:
java
运行
import lombok.Builder;
import lombok.ToString;
@Builder // 自动生成静态内部Builder类 + 链式方法 + build()方法
@ToString
public class Computer {
private String cpu;
private String memory;
private String hardDisk;
private String graphics;
private String os;
}
// 客户端使用
public class Client {
public static void main(String[] args) {
Computer computer = Computer.builder()
.cpu("Intel i9")
.memory("32GB")
.graphics("RTX 4090")
.build();
System.out.println(computer);
}
}
4. 建造者模式的坑
- 不要滥用:简单对象(比如只有 2-3 个属性)用建造者模式会增加代码冗余,直接用构造器 /setter 即可;
- 注意线程安全:如果 Builder 被多线程调用,需要加锁(但 Builder 通常是局部变量,无需考虑);
- 参数校验:必须在
build()方法中校验必填属性,否则会创建 "半成品" 对象; - 避免过度设计:经典版的 Director 和抽象 Builder 只在流程固定时使用,业务层优先用简化版。
五、建造者模式与其他创建型模式的区别
1. 建造者模式 vs 工厂模式
| 维度 | 建造者模式 | 工厂模式(简单工厂 / 工厂方法) |
|---|---|---|
| 核心目标 | 关注如何一步步构建复杂对象 | 关注创建什么对象(不关心构建过程) |
| 产品特点 | 同一产品的不同配置(比如游戏本和办公本都是电脑,只是配置不同) | 不同产品的不同类型(比如工厂生产电脑、手机、平板) |
| 调用方式 | 链式调用多个方法,最后 build () | 调用一个方法直接获取对象 |
| 适用场景 | 复杂对象、配置灵活 | 简单对象、类型固定 |
2. 建造者模式 vs 原型模式
- 建造者模式:从头开始构建对象(一步一步组装部件);
- 原型模式:复制已有对象(基于原型克隆,无需重新构建)。
六、实战场景举例(无人售货柜项目)
以无人售货柜的 "订单对象" 为例,订单包含:
- 必填属性:订单号、设备 ID、用户 ID、商品列表、支付金额;
- 可选属性:优惠券 ID、配送地址、备注、支付方式;
- 依赖关系:"选择配送模式" 必须填写配送地址。
用建造者模式实现:
java
运行
public class VendingOrder {
// 必填属性
private final String orderId;
private final String machineId;
private final String userId;
private final List<String> productIds;
private final BigDecimal payAmount;
// 可选属性
private String couponId;
private String deliveryAddress;
private String remark;
private String payType;
// 私有化构造器
private VendingOrder(Builder builder) {
this.orderId = builder.orderId;
this.machineId = builder.machineId;
this.userId = builder.userId;
this.productIds = builder.productIds;
this.payAmount = builder.payAmount;
this.couponId = builder.couponId;
this.deliveryAddress = builder.deliveryAddress;
this.remark = builder.remark;
this.payType = builder.payType;
// 校验依赖关系:配送模式必须填地址
if ("DELIVERY".equals(payType) && (deliveryAddress == null || deliveryAddress.isEmpty())) {
throw new IllegalArgumentException("配送模式必须填写配送地址");
}
}
// 静态内部建造者
public static class Builder {
// 必填属性(final强制初始化)
private final String orderId;
private final String machineId;
private final String userId;
private final List<String> productIds;
private final BigDecimal payAmount;
// 可选属性
private String couponId;
private String deliveryAddress;
private String remark;
private String payType = "WECHAT"; // 默认微信支付
// 构造器:强制传入必填属性
public Builder(String orderId, String machineId, String userId, List<String> productIds, BigDecimal payAmount) {
this.orderId = orderId;
this.machineId = machineId;
this.userId = userId;
this.productIds = productIds;
this.payAmount = payAmount;
}
// 链式方法
public Builder couponId(String couponId) {
this.couponId = couponId;
return this;
}
public Builder deliveryAddress(String deliveryAddress) {
this.deliveryAddress = deliveryAddress;
return this;
}
public Builder remark(String remark) {
this.remark = remark;
return this;
}
public Builder payType(String payType) {
this.payType = payType;
return this;
}
// 构建订单
public VendingOrder build() {
// 基础校验
if (productIds == null || productIds.isEmpty()) {
throw new IllegalArgumentException("订单商品列表不能为空");
}
if (payAmount.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("支付金额必须大于0");
}
return new VendingOrder(this);
}
}
@Override
public String toString() {
return "VendingOrder{" +
"orderId='" + orderId + '\'' +
", machineId='" + machineId + '\'' +
", userId='" + userId + '\'' +
", productIds=" + productIds +
", payAmount=" + payAmount +
", couponId='" + couponId + '\'' +
", deliveryAddress='" + deliveryAddress + '\'' +
", remark='" + remark + '\'' +
", payType='" + payType + '\'' +
'}';
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
List<String> productIds = Arrays.asList("PROD001", "PROD002");
// 构建配送订单(必须填配送地址)
VendingOrder deliveryOrder = new VendingOrder.Builder(
"ORDER001",
"VM001",
"USER001",
productIds,
new BigDecimal("99.9")
)
.payType("DELIVERY")
.deliveryAddress("北京市海淀区XX街道")
.couponId("COUPON001")
.build();
// 构建自提订单(无需配送地址)
VendingOrder pickUpOrder = new VendingOrder.Builder(
"ORDER002",
"VM001",
"USER001",
productIds,
new BigDecimal("89.9")
)
.payType("PICK_UP")
.remark("请尽快自提")
.build();
System.out.println("配送订单:" + deliveryOrder);
System.out.println("自提订单:" + pickUpOrder);
}
}
七、总结
核心要点
- 建造者模式的核心是分离 "构建流程" 和 "具体配置",既保证构建过程标准化,又支持配置个性化;
- 实战中优先使用静态内部类 + 链式调用的简化版,经典版(Director+Builder)仅用于流程固定的场景;
- 适用场景:复杂对象(多必填 + 多可选属性)、需要控制构建顺序、避免创建不完整对象。
关键提醒
- 不要滥用:简单对象(≤3 个属性)无需使用,直接用构造器 /setter 即可;
- 必做校验:在
build()方法中校验必填属性和属性依赖关系,避免半成品对象; - 简化开发:用 Lombok 的
@Builder注解减少重复代码,提升开发效率。
建造者模式是业务开发中最常用的设计模式之一,掌握它能让你构建复杂对象时更优雅、更安全,避免写出 "参数爆炸" 的糟糕代码。