Java设计模式精讲---03建造者模式
在软件开发中,我们经常需要创建一些包含多个组成部分的复杂对象。比如一台电脑由 CPU、内存、硬盘、显卡等部件组成;一份简历包含基本信息、教育经历、工作经历、项目经验等模块。如果直接通过构造函数或 setter 方法来组装这些对象,不仅会导致代码臃肿、参数混乱,还难以灵活应对不同组合的需求。
今天我们来聊聊一种专门解决这类问题的设计模式 ——建造者模式,看看它如何像 “搭积木” 一样优雅地构建复杂对象。
一、什么是建造者模式
建造者模式的核心思想是:将一个复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建出不同的表示。
简单来说,就是把 “怎么组装零件” 和 “最终组装出什么产品” 分开。比如同样是组装电脑,“先装 CPU 再装内存最后装硬盘” 这个流程可以不变,但可以根据需求组装出 “游戏本”或 “办公本”。
二、建造者模式解决什么问题
假设我们要创建一个Computer类,如果用传统方式创建,可能会写出这样的代码:
// 传统方式:构造函数参数爆炸
public class Computer {public Computer(String cpu, String memory, String hardDisk, String gpu, String os) {// 初始化逻辑}
}// 使用时需要记住参数顺序,新增参数还要改构造函数
Computer gamePC = new Computer("i9-13900K", "32GB", "1TB SSD", "RTX 4090", "Windows 11");这种方式的问题很明显:
- 参数过多,容易传错顺序;
- 如果需要创建不同配置(比如办公本不需要独立显卡),得重载多个构造函数,代码冗余;
- 构建过程(比如 “必须先装 CPU 才能装内存”)无法控制,容易出现无效对象。
而建造者模式就能完美解决这些问题:它将构建步骤拆分,通过 “一步步设置” 的方式组装对象,同时隐藏复杂的构建逻辑。
三、建造者模式的核心角色
建造者模式包含 4 个核心角色,我们用 “组装电脑” 的例子来理解:
产品:被构建的复杂对象(比如
Computer),包含多个组成部分。抽象建造者:定义构建产品的抽象步骤(比如 “装 CPU”“装内存”),以及返回最终产品的方法。它不关心具体怎么实现,只规定 “要做哪些事”。
具体建造者:实现抽象建造者的步骤,负责具体的零件组装(比如
GameComputerBuilder实现 “装高性能 CPU”“装独立显卡”)。指挥者:负责控制构建流程(比如 “先装 CPU→再装内存→最后装系统”),它调用具体建造者的方法,按照固定流程组装产品,用户不需要关心步骤细节。
四、代码实现:用建造者模式组装电脑
我们通过代码来实现 “组装电脑” 的例子,看看建造者模式如何落地。
1. 定义产品
首先是被构建的对象Computer,它包含多个部件:
// 产品:电脑
public class Computer {private String cpu; // CPUprivate String memory; // 内存private String hardDisk; // 硬盘private String gpu; // 显卡private String os; // 操作系统// 私有构造函数,避免外部直接创建private Computer() {}// getter方法(便于查看结果)public String getCpu() { return cpu; }public String getMemory() { return memory; }public String getHardDisk() { return hardDisk; }public String getGpu() { return gpu; }public String getOs() { return os; }// 内部静态类:用于修改私有属性(建造者需要访问)public static class Builder {private Computer computer;public Builder() {computer = new Computer();}// 逐步设置属性的方法(返回Builder本身,支持链式调用)public Builder setCpu(String cpu) {computer.cpu = cpu;return this;}public Builder setMemory(String memory) {computer.memory = memory;return this;}public Builder setHardDisk(String hardDisk) {computer.hardDisk = hardDisk;return this;}public Builder setGpu(String gpu) {computer.gpu = gpu;return this;}public Builder setOs(String os) {computer.os = os;return this;}// 返回最终构建的产品public Computer build() {return computer;}}
}这里用了一个内部静态 Builder 类(简化版建造者),它可以直接访问Computer的私有属性,同时支持链式调用(每个 set 方法返回Builder本身)。
2. 定义具体建造者
根据需求,我们创建两种具体建造者:游戏本建造者和办公本建造者:
// 具体建造者1:游戏本建造者
public class GameComputerBuilder {private Computer.Builder builder;public GameComputerBuilder() {builder = new Computer.Builder();}// 构建游戏本的方法(预设高性能配件)public void buildGameComputer() {builder.setCpu("i9-13900K").setMemory("32GB DDR5").setHardDisk("1TB SSD").setGpu("RTX 4090").setOs("Windows 11");}// 返回构建好的电脑public Computer getResult() {return builder.build();}
}// 具体建造者2:办公本建造者
public class OfficeComputerBuilder {private Computer.Builder builder;public OfficeComputerBuilder() {builder = new Computer.Builder();}// 构建办公本的方法(预设稳定低耗配件)public void buildOfficeComputer() {builder.setCpu("i5-13400").setMemory("16GB DDR4").setHardDisk("512GB SSD").setGpu("集成显卡") // 办公本无需独立显卡.setOs("Windows 10");}public Computer getResult() {return builder.build();}
}3. 定义指挥者
指挥者负责控制构建流程,确保步骤正确:
// 指挥者:负责控制电脑组装流程
public class ComputerDirector {// 指挥建造者按照流程构建产品public Computer construct(GameComputerBuilder builder) {builder.buildGameComputer(); // 调用游戏本的构建方法return builder.getResult();}public Computer construct(OfficeComputerBuilder builder) {builder.buildOfficeComputer(); // 调用办公本的构建方法return builder.getResult();}
}4. 测试代码
最后我们用客户端代码测试一下:
public class Client {public static void main(String[] args) {// 创建指挥者ComputerDirector director = new ComputerDirector();// 构建游戏本GameComputerBuilder gameBuilder = new GameComputerBuilder();Computer gamePC = director.construct(gameBuilder);System.out.println("游戏本配置:");System.out.println("CPU:" + gamePC.getCpu());System.out.println("显卡:" + gamePC.getGpu());// 构建办公本OfficeComputerBuilder officeBuilder = new OfficeComputerBuilder();Computer officePC = director.construct(officeBuilder);System.out.println("\n办公本配置:");System.out.println("CPU:" + officePC.getCpu());System.out.println("显卡:" + officePC.getGpu());}
}输出结果:
游戏本配置:
CPU:i9-13900K
显卡:RTX 4090办公本配置:
CPU:i5-13400
显卡:集成显卡
五、建造者模式的优缺点
优点:
- 解耦构建与表示:构建过程(步骤)和产品(结果)分离,同一过程可创建不同产品。
- 控制构建过程:指挥者可以严格控制构建步骤,避免无效对象(比如 “没装 CPU 就装内存”)。
- 灵活扩展:新增产品只需新增具体建造者,无需修改原有代码(符合开闭原则)。
- 代码清晰:通过链式调用或分步构建,避免了多参数构造函数的混乱。
缺点:
- 类数量增加:每个产品都需要对应具体建造者,若产品复杂且多样,会导致类数量增多。
- 适用场景有限:只适合构建 “组成部分相似” 的复杂对象,若产品差异过大(比如电脑和手机),不适合用建造者模式。
六、适用场景
建造者模式适合以下场景:
- 构建包含多个组成部分的复杂对象(如电脑、简历、文档)。
- 需要控制对象构建流程(如必须按顺序设置属性)。
- 同一构建过程需要生成不同表示(如同一流程组装不同配置的产品)。
常见的实际应用:
- Java 中的
StringBuilder(通过append方法逐步构建字符串)。 - 很多框架的配置类(如 Spring 的
ResourceBuilder)。 - 建造者模式的简化版(内部 Builder 类)广泛用于 POJO 对象的创建(避免多参数构造函数)。
七、建造者模式 vs 抽象工厂模式
昨天我们讲了抽象工厂模式,它和建造者模式都用于创建对象,但核心区别在于:
- 抽象工厂模式:关注 “创建一系列相关产品”(如创建电脑的同时创建配套的键盘、鼠标),不关心产品的组装过程。
- 建造者模式:关注 “一个复杂产品的逐步构建”,核心是控制组装步骤,最终产出一个完整对象。
简单说:抽象工厂是 “批量生产相关零件”,建造者是 “用零件一步步拼出一个成品”。
总结
建造者模式通过分离 “构建过程” 和 “产品表示”,让复杂对象的创建变得清晰、灵活。它特别适合需要精细控制组装步骤、或同一流程需生成不同产品的场景。
如果你的代码中出现了 “参数爆炸” 的构造函数,或需要频繁创建不同组合的复杂对象,不妨试试建造者模式 —— 它会像一位耐心的工匠,帮你一步步搭建出完美的 “产品”。
