一、建造者模式的核心定义
建造者模式是一种创建型设计模式 ,核心思想是:将复杂对象的构建过程与它的表示分离,使得同样的构建流程可以创建出不同的对象实例。
简单比喻:就像你去奶茶店点奶茶 ------ 构建一杯奶茶的 "流程" 是固定的(选基底、选甜度、选配料、加冰 / 热),但每一步的 "具体选择" 可以不同(比如基底选红茶 / 绿茶,甜度选三分 / 五分),最终能做出不同口味的奶茶。建造者模式就是把 "流程(步骤)" 和 "具体实现(选择)" 分开,让构建过程更清晰、灵活。
二、为什么需要建造者模式?
它主要解决以下问题
- 避免 "臃肿的构造函数" :当一个对象有很多属性(尤其是可选属性)时,直接用构造函数会导致参数列表过长(比如
new Computer("i9", 32, "1T", "4090", "Windows")),可读性差且易出错; - 保证对象状态统一 :如果用
setter方法逐个设置属性,对象在构造过程中可能处于 "不完整状态"(比如只设了 CPU 没设内存就被调用); - 解耦构建流程和细节:构建步骤固定,但每个步骤的实现可灵活替换,便于扩展。
优点
- 分离构建过程和表示,使得构建过程更加灵活,可以构建不同的表示。
- 可以更好地控制构建过程,隐藏具体构建细节。
- 代码复用性高,可以在不同的构建过程中重复使用相同的建造者。
缺点
- 如果产品的属性较少,建造者模式可能会导致代码冗余。
- 增加了系统的类和对象数量。
三、建造者模式的核心角色
| 角色 | 作用 |
|---|---|
| 产品(Product) | 要构建的复杂对象(比如电脑、奶茶、汽车) |
| 抽象建造者(Builder) | 定义构建产品的所有步骤(比如 "设置 CPU""设置内存"),通常是接口 / 抽象类 |
| 具体建造者(ConcreteBuilder) | 实现抽象建造者的方法,完成具体产品的构建(比如 "游戏本建造者""办公本建造者") |
| 指挥者(Director) | 可选角色,负责按固定顺序调用建造步骤,控制整体构建流程 |
四、代码示例(Java 实现)
以 "构建电脑" 为例,电脑有必选属性(CPU、内存)和可选属性(硬盘、显卡、系统),用建造者模式实现:
1. 产品类(Computer)
// 要构建的复杂对象:电脑
public class Computer {
// 必选属性
private String cpu;
private int ram;
// 可选属性
private String hardDisk;
private String graphicsCard;
private String os;
// 私有化构造方法,只能通过Builder创建
private Computer(Builder builder) {
this.cpu = builder.cpu;
this.ram = builder.ram;
this.hardDisk = builder.hardDisk;
this.graphicsCard = builder.graphicsCard;
this.os = builder.os;
}
// 静态内部建造者类(最常用的简化写法,省略Director)
public static class Builder {
// 必选属性(必须在Builder构造时传入)
private String cpu;
private int ram;
// 可选属性(默认值或按需设置)
private String hardDisk = "512G SSD"; // 默认硬盘
private String graphicsCard = "集成显卡"; // 默认显卡
private String os = "Windows 10"; // 默认系统
// Builder构造方法:强制传入必选属性
public Builder(String cpu, int ram) {
this.cpu = cpu;
this.ram = ram;
}
// 可选属性的设置方法,返回Builder本身(链式调用)
public Builder hardDisk(String hardDisk) {
this.hardDisk = hardDisk;
return this;
}
public Builder graphicsCard(String graphicsCard) {
this.graphicsCard = graphicsCard;
return this;
}
public Builder os(String os) {
this.os = os;
return this;
}
// 构建方法:创建Computer实例
public Computer build() {
// 可选:在这里做参数校验,确保对象完整
if (cpu == null || ram <= 0) {
throw new IllegalArgumentException("CPU和内存不能为空!");
}
return new Computer(this);
}
}
// 重写toString,方便查看结果
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", ram=" + ram + "G" +
", hardDisk='" + hardDisk + '\'' +
", graphicsCard='" + graphicsCard + '\'' +
", os='" + os + '\'' +
'}';
}
}
2. 测试代码(使用建造者创建对象)
public class BuilderTest {
public static void main(String[] args) {
// 构建"办公本":只用必选属性+默认可选属性
Computer officeComputer = new Computer.Builder("i5-13400", 16)
.build();
System.out.println("办公本:" + officeComputer);
// 构建"游戏本":必选属性+自定义可选属性(链式调用)
Computer gameComputer = new Computer.Builder("i9-14900K", 32)
.hardDisk("2T SSD")
.graphicsCard("RTX 4090")
.os("Windows 11")
.build();
System.out.println("游戏本:" + gameComputer);
}
}
3. 运行结果
办公本:Computer{cpu='i5-13400', ram=16G, hardDisk='512G SSD', graphicsCard='集成显卡', os='Windows 10'}
游戏本:Computer{cpu='i9-14900K', ram=32G, hardDisk='2T SSD', graphicsCard='RTX 4090', os='Windows 11'}
五、代码关键说明
-
私有化产品构造方法:确保只能通过 Builder 创建对象,避免对象状态不完整;
// 私有化构造方法,只能通过Builder创建Computer实例
private Computer(Builder builder) {
this.cpu = builder.cpu;
this.ram = builder.ram;
this.hardDisk = builder.hardDisk;
this.graphicsCard = builder.graphicsCard;
this.os = builder.os;
}
核心作用:禁止外部通过new Computer()直接创建对象 ,必须通过内部的Builder类来创建,保证对象创建的可控性;
赋值逻辑:从Builder对象中读取配置好的属性值,赋值给Computer的属性(Builder 相当于 "配置器")。
-
静态内部 Builder 类:这是最常用的简化写法(省略 Director),符合 "迪米特法则";
Builder 的构造方法(强制传入必选属性)
// Builder构造方法:强制传入必选属性
public Builder(String cpu, int ram) {
this.cpu = cpu;
this.ram = ram;
}
核心作用:强制要求创建 Builder 时必须传入 CPU 和内存,从源头保证必选属性不缺失;
举例:如果写new Computer.Builder()会直接编译报错,必须写new Computer.Builder("i5", 16)。
-
链式调用 :每个可选属性的设置方法返回
this,让代码更简洁(builder.xx().yy().build());// 可选属性的设置方法,返回Builder本身(链式调用)
public Builder hardDisk(String hardDisk) {
this.hardDisk = hardDisk;
return this;
}public Builder graphicsCard(String graphicsCard) {
this.graphicsCard = graphicsCard;
return this;
}public Builder os(String os) {
this.os = os;
return this;
}
核心设计:每个方法执行完属性赋值后,返回this(当前 Builder 对象),这是 "链式调用" 的关键;
效果:可以写builder.hardDisk("2T SSD").graphicsCard("RTX4090").os("Windows11"),代码简洁且可读性高;
对比:如果不返回this,需要写builder.hardDisk("2T SSD"); builder.graphicsCard("RTX4090");,代码冗余。
-
参数校验 :在
build()方法中校验必选属性,保证对象合法性。// 构建方法:创建Computer实例
public Computer build() {
// 可选:在这里做参数校验,确保对象完整
if (cpu == null || ram <= 0) {
throw new IllegalArgumentException("CPU和内存不能为空!");
}
return new Computer(this);
}
核心作用:触发Computer对象的创建,是建造者模式的 "收尾步骤";
参数校验:额外增加合法性检查(比如 CPU 不能为 null、内存不能≤0),即使通过了 Builder 构造方法,也能防止传入非法值(比如new Builder(null, -8));
异常类型:IllegalArgumentException是 Java 标准异常,用于表示 "参数不合法",符合语义。
六、建造者模式的实际应用场景
- SDK / 框架设计 :比如 Java 的
StringBuilder(本质是简化的建造者模式,构建复杂字符串)、MyBatis 的SqlSessionFactoryBuilder; - 复杂对象创建:比如创建订单(包含收货人、商品、支付方式、物流等多属性)、配置对象(比如连接池配置);
- 生成器工具:比如 JSON/XML 生成器(固定的构建步骤,不同内容对应不同表示)。
七、总结
- 建造者模式的核心是分离 "构建步骤" 和 "具体实现",解决复杂对象的创建问题;
- 最常用的形式是静态内部 Builder 类 + 链式调用,无需单独的 Director 角色,简洁易用;
- 它的核心价值是保证对象创建的灵活性和安全性,避免臃肿构造函数和不完整对象
八、扩展
一、带 Director 角色的完整建造者模式(Java 实现)
带 Director 的版本更贴合建造者模式的经典定义,Director 负责 "把控构建流程",具体建造者负责 "实现构建细节",完全解耦流程和实现。依然以 "构建电脑" 为例:
1. 产品类(Product):Computer
// 要构建的复杂对象:电脑(和之前一致,仅调整访问权限适配Builder)
public class Computer {
private String cpu;
private int ram;
private String hardDisk;
private String graphicsCard;
private String os;
// 空构造(让Builder可以设置属性)
public Computer() {}
// setter方法(供Builder调用)
public void setCpu(String cpu) {
this.cpu = cpu;
}
public void setRam(int ram) {
this.ram = ram;
}
public void setHardDisk(String hardDisk) {
this.hardDisk = hardDisk;
}
public void setGraphicsCard(String graphicsCard) {
this.graphicsCard = graphicsCard;
}
public void setOs(String os) {
this.os = os;
}
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", ram=" + ram + "G" +
", hardDisk='" + hardDisk + '\'' +
", graphicsCard='" + graphicsCard + '\'' +
", os='" + os + '\'' +
'}';
}
}
2. 抽象建造者(Builder):ComputerBuilder
定义构建电脑的所有核心步骤,是具体建造者的 "规范":
// 抽象建造者:定义构建电脑的所有步骤
public abstract class ComputerBuilder {
// 持有产品对象,供子类设置属性
protected Computer computer = new Computer();
// 必选构建步骤(抽象方法,子类必须实现)
public abstract void buildCpu();
public abstract void buildRam();
// 可选构建步骤(默认实现,子类可重写)
public void buildHardDisk() {
computer.setHardDisk("512G SSD"); // 默认值
}
public void buildGraphicsCard() {
computer.setGraphicsCard("集成显卡"); // 默认值
}
public void buildOs() {
computer.setOs("Windows 10"); // 默认值
}
// 构建完成,返回产品
public Computer getComputer() {
return computer;
}
}
3. 具体建造者(ConcreteBuilder)
实现抽象建造者的步骤,完成 "游戏本" 和 "办公本" 的具体构建:
// 具体建造者1:游戏本建造者
public class GameComputerBuilder extends ComputerBuilder {
@Override
public void buildCpu() {
computer.setCpu("i9-14900K"); // 游戏本高性能CPU
}
@Override
public void buildRam() {
computer.setRam(32); // 游戏本32G内存
}
// 重写可选步骤,自定义游戏本配置
@Override
public void buildHardDisk() {
computer.setHardDisk("2T SSD");
}
@Override
public void buildGraphicsCard() {
computer.setGraphicsCard("RTX 4090");
}
@Override
public void buildOs() {
computer.setOs("Windows 11");
}
}
// 具体建造者2:办公本建造者
public class OfficeComputerBuilder extends ComputerBuilder {
@Override
public void buildCpu() {
computer.setCpu("i5-13400"); // 办公本中等CPU
}
@Override
public void buildRam() {
computer.setRam(16); // 办公本16G内存
}
// 可选步骤用默认值,无需重写
}
4. 指挥者(Director)
负责固定构建流程,调用建造者的步骤,控制 "先建什么、后建什么":
// 指挥者:控制电脑的构建流程
public class ComputerDirector {
// 构建方法:传入具体建造者,按固定流程构建
public Computer constructComputer(ComputerBuilder builder) {
// 固定构建顺序:CPU → 内存 → 硬盘 → 显卡 → 系统
builder.buildCpu();
builder.buildRam();
builder.buildHardDisk();
builder.buildGraphicsCard();
builder.buildOs();
return builder.getComputer();
}
}
5. 测试代码(使用 Director 构建对象)
public class DirectorBuilderTest {
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);
}
}
6. 运行结果
游戏本:Computer{cpu='i9-14900K', ram=32G, hardDisk='2T SSD', graphicsCard='RTX 4090', os='Windows 11'}
办公本:Computer{cpu='i5-13400', ram=16G, hardDisk='512G SSD', graphicsCard='集成显卡', os='Windows 10'}
关键说明(Director 的作用)
- Director 是 "流程指挥官":它定义了 "先建 CPU、再建内存、最后建系统" 的固定流程,不管传入哪个具体建造者,都按这个流程构建;
- 具体建造者是 "细节执行者":只负责实现每个步骤的具体内容(比如游戏本用 i9,办公本用 i5);
- 扩展灵活:如果要新增 "轻薄本",只需新增
LightComputerBuilder,无需修改 Director 和其他代码(符合开闭原则)。
二、建造者模式 vs 工厂模式(核心区别)
很多新手会混淆这两种创建型模式,核心差异在于 "创建的关注点" 和 "使用场景",用表格和通俗比喻清晰对比:
| 维度 | 建造者模式 | 工厂模式(简单工厂 / 工厂方法 / 抽象工厂) |
|---|---|---|
| 核心目的 | 构建复杂对象(多属性、多步骤),控制构建流程 | 创建简单 / 复杂对象,快速获取实例 |
| 创建方式 | 分步骤构建(一步步设置属性 / 组件),最后组装成对象 | 一次性创建(调用方法直接返回完整对象) |
| 关注点 | 关注 "如何构建"(步骤、流程、细节) | 关注 "创建谁"(选择哪个对象实例) |
| 对象属性灵活性 | 高:可自定义多个可选属性,支持链式配置 | 低:通常返回固定配置的对象 |
| 代码特征 | 有明确的 "步骤方法"+"build/construct" 方法 | 有明确的 "工厂方法"(如createXXX()) |
| 通俗比喻 | 拼乐高:按步骤拼出不同造型(流程固定,零件可选) | 去便利店买水:说 "买矿泉水" 直接拿到,不用管怎么生产 |
| 典型使用场景 | 1. 多属性对象(订单、配置、电脑)2. 需控制构建流程3. 避免臃肿构造函数 | 1. 快速创建单一类型对象(如ShapeFactory.createCircle())2. 解耦对象创建和使用3. 统一对象创建入口 |
| 典型例子 | StringBuilder、MyBatis 的SqlSessionFactoryBuilder、OkHttp 的Request.Builder |
Calendar.getInstance()、Spring 的BeanFactory、简单工厂创建图形 |
补充:何时选建造者,何时选工厂?
- 如果你需要自定义对象的多个属性(比如电脑的 CPU、内存、显卡都要选)→ 用建造者模式;
- 如果你只需要获取一个固定类型的对象(比如 "我要一个圆形""我要一个 MySQL 连接池")→ 用工厂模式;
- 建造者模式是 "定制化生产",工厂模式是 "标准化量产"。
总结
- 带 Director 的建造者模式:通过 "抽象 Builder 定步骤、具体 Builder 做实现、Director 控流程",完全解耦构建流程和细节,适合需要统一构建流程的场景;
- 简化版建造者(静态内部类):省略 Director,通过链式调用直接构建,更简洁,日常开发中使用更广;
- 建造者 vs 工厂:核心差异是 "分步骤定制构建" vs "一次性标准化创建",前者关注 "怎么建",后者关注 "建什么"。

