1. 什么是建造者模式
建造者模式(Builder Pattern)是 GoF 23种设计模式中对象创建型设计模式之一,其核心思想是把复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表示。
2.为什么需要建造者模式
当对象的构造过程涉及多个步骤、多个可选参数或参数之间有依赖关系时,直接使用构造函数或工厂方法会导致:
- 构造函数参数列表过长(
telescoping constructor反模式) - 可选参数组合爆炸
- 对象状态不一致的风险
- 可读性差,难以维护
3. 角色与UML
classDiagram
class Computer {
-cpu: String
-ram: String
-disk: String
+setCpu(String)
+setRam(String)
+setDisk(String)
+toString() String
}
class ComputerBuilder {
#computer: Computer
+buildCpu()* void
+buildRam()* void
+buildDisk()* void
+getResult() Computer
}
class GamingComputerBuilder {
+buildCpu() void
+buildRam() void
+buildDisk() void
}
class OfficeComputerBuilder {
+buildCpu() void
+buildRam() void
+buildDisk() void
}
class Director {
+construct(ComputerBuilder) Computer
}
class Client {
+main(String[]) void
}
ComputerBuilder <|-- GamingComputerBuilder : extends
ComputerBuilder <|-- OfficeComputerBuilder : extends
ComputerBuilder --> Computer : creates/uses
Director --> ComputerBuilder : uses
Client --> Director : uses
Client ..> GamingComputerBuilder : creates
Client ..> OfficeComputerBuilder : creates
| 类 / 接口 | 模式中的角色 | 作用与职责 |
|---|---|---|
| Computer | 产品(Product) | 被逐步装配的复杂对象;仅含 getter / setter,不感知建造过程。 |
| ComputerBuilder | 抽象建造者(Builder) | 定义创建各部件的抽象接口;持有 / 返回产品实例。 |
| GamingComputerBuilder | 具体建造者(ConcreteBuilder) | 实现抽象接口,给出游戏电脑各部件的具体装配算法;产出对应产品。 |
| OfficeComputerBuilder | 具体建造者(ConcreteBuilder) | 实现抽象接口,给出办公电脑各部件的具体装配算法;产出对应产品。 |
| Director | 指挥者(Director) | 持有抽象建造者引用,按固定顺序调用 buildXxx(),封装完整装配流程。 |
| Client | 客户端(Client) | 选择具体建造者并交给 Director,最终取回完整产品;不依赖具体建造者细节。 |
4. Java代码示例
1、产品
public class Computer {
private String cpu;
private String ram;
private String disk;
public void setCpu(String cpu) { this.cpu = cpu; }
public void setRam(String ram) { this.ram = ram; }
public void setDisk(String disk) { this.disk = disk; }
@Override
public String toString() {
return "Computer{cpu='" + cpu + "', ram='" + ram + "', disk='" + disk + "'}";
}
}
2、抽象建造者
public abstract class ComputerBuilder {
protected Computer computer = new Computer();
public abstract void buildCpu();
public abstract void buildRam();
public abstract void buildDisk();
public Computer getResult() { return computer; }
}
3、具体建造者
public class GamingComputerBuilder extends ComputerBuilder {
public void buildCpu() { computer.setCpu("i9-13900K"); }
public void buildRam() { computer.setRam("32GB DDR5"); }
public void buildDisk() { computer.setDisk("2TB NVMe SSD"); }
}
public class OfficeComputerBuilder extends ComputerBuilder {
public void buildCpu() { computer.setCpu("i5-12400"); }
public void buildRam() { computer.setRam("16GB DDR4"); }
public void buildDisk() { computer.setDisk("512GB SATA SSD"); }
}
4、指挥者
public class Director {
public Computer construct(ComputerBuilder builder) {
builder.buildCpu();
builder.buildRam();
builder.buildDisk();
return builder.getResult();
}
}
5、客户端
public class Client {
public static void main(String[] args) {
Director director = new Director();
Computer gaming = director.construct(new GamingComputerBuilder());
Computer office = director.construct(new OfficeComputerBuilder());
System.out.println(gaming); // Computer{cpu='i9-13900K', ram='32GB DDR5', disk='2TB NVMe SSD'}
System.out.println(office); // Computer{cpu='i5-12400', ram='16GB DDR4', disk='512GB SATA SSD'}
}
}
运行结果
Computer{cpu='i9-13900K', ram='32GB DDR5', disk='2TB NVMe SSD'}
Computer{cpu='i5-12400', ram='16GB DDR4', disk='512GB SATA SSD'}
5. 优缺点
| 维度 | 优点(Pros) | 缺点(Cons) |
|---|---|---|
| 复杂性 | 把“构建步骤”与“表示”分离,客户端无需了解装配细节,降低认知负担。 | 类数量翻倍(Builder+ConcreteBuilder+Director),小系统容易过度设计。 |
| 扩展性 | 新增产品时只加 ConcreteBuilder,符合开闭原则(OCP)。 | 若装配算法本身多变,Director 会变得越来越臃肿,难以复用。 |
| 复用性 | 同一 Director 可复用于不同 ConcreteBuilder,得到不同表示(游戏本/办公本)。 | Product 必须提供可写接口(setXxx),与“不可变对象”理念冲突,需额外拷贝。 |
| 一致性 | 集中控制构造顺序与默认值,避免散落在各处 new 语句,保证对象完整性。 | 多线程场景下,Builder 状态共享需额外同步,否则可能构造出“半成品”对象。 |
| 运行时 | 可在运行期动态切换 ConcreteBuilder,实现“同流程、多产品”的灵活配置。 | 对简单对象(字段<4)来说,代码量远大于直接构造函数或静态工厂,得不偿失。 |
6. 典型应用
- OkHttp 连接池、拦截器、超时等复杂参数先写 Builder,真正
build()时才生成不可变OkHttpClient,可安全复用。 - MyBatis 解析 XML 时按顺序
parse()→eval()→ 封装成Configuration,保证 Mapper 接口与 SQL 一次性绑定成功。
一句话总结:只要 配置项多、对象要不可变、构造过程要可扩展 这三个条件同时出现时可直接采用Builder模式。