第 4 天:建造者模式(Builder Pattern)—— 创建型模式

1. 核心定义

建造者模式将一个复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表示。它的核心是 "分步构建 + 统一组装":先按固定步骤拆解对象的构建流程(如造汽车分 "装底盘→装发动机→装座椅→喷漆"),再由专门的 "指挥者" 控制步骤顺序,最终生成完整对象。

简单来说:复杂对象像 "乐高模型",建造者负责 "拼每一块零件",指挥者负责 "按说明书顺序拼",客户端只需 "要最终的模型",无需关心零件怎么拼、顺序是什么。

2. 解决的核心问题

当创建的对象满足以下特征时,传统 new 关键字或工厂模式会变得非常繁琐:

  • 属性多且可选 :如创建一个 "用户对象",包含姓名(必选)、年龄(可选)、手机号(可选)、地址(可选)、角色(可选)等 10 + 属性,若用构造函数,需重载多个版本(如 User(name)User(name, age)User(name, age, phone)...),代码臃肿;
  • 构建步骤固定且复杂:如创建 "电脑对象",必须按 "装主板→装 CPU→装内存→装硬盘→装电源" 的顺序,步骤不能乱,且每个步骤有细节逻辑(如装 CPU 需涂硅脂),直接写在构造函数里会导致逻辑混乱、难以维护;
  • 需要不同表示:同一构建步骤可生成不同结果(如同样是 "造蛋糕",步骤都是 "打胚→抹奶油→装饰",但装饰步骤可做成 "水果蛋糕" 或 "巧克力蛋糕")。

建造者模式的解决方案:

  • 用 "建造者" 封装每个步骤的细节(如 ComputerBuilderbuildMotherboard()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. 应用场景

建造者模式的核心是 "复杂对象的分步构建",适合以下场景:

  1. 复杂对象创建:对象包含多个组成部分,且构建步骤固定(如汽车、电脑、手机等硬件;文档、报表等软件对象);
  2. 属性多且可选:对象有大量可选属性,需避免重载多个构造函数(如用户、订单、配置类,对应简化版流式建造者);
  3. 需不同表示:同一构建步骤需生成不同结果(如蛋糕(水果 / 巧克力)、文档(PDF/Word))。

经典实战案例

  • JDK 中的 StringBuilder/StringBuffer:本质是简化的建造者,append() 方法对应 "分步构建字符串",toString() 对应 "返回最终产品";
  • 框架中的对象构建:如 MyBatis 的 SqlSessionFactoryBuilder、Spring 的 BeanDefinitionBuilder,均通过分步调用方法构建复杂对象;
  • 工具类生成:如 Lombok 的 @Builder 注解,自动为类生成流式建造者,避免手动编写建造者代码。

7. 优缺点分析

优点 缺点
1. 解耦构建与表示:构建步骤由建造者封装,产品表示由具体建造者决定,客户端无需关心细节;2. 灵活控制构建过程:指挥者可调整步骤顺序,具体建造者可修改步骤逻辑,生成不同产品;3. 便于扩展:新增产品表示只需加 "具体建造者",无需改指挥者和产品(符合开闭原则);4. 校验方便:在 build() 方法中可对属性进行校验(如必选属性非空)。 1. 类结构复杂:完整模式需 "产品 + 抽象建造者 + 具体建造者 + 指挥者",类数量多;2. 适用范围有限:仅适合 "复杂对象",若对象简单(如只有 2 个属性),用建造者反而冗余。

8. 与工厂方法模式的核心区别

建造者模式和工厂方法模式都属于创建型模式,但关注点完全不同:

对比维度 工厂方法模式 建造者模式
核心目标 解决 "创建哪类对象" 的问题(如创建手机还是平板) 解决 "如何分步构建复杂对象" 的问题(如手机如何装屏幕、电池)
关注重点 产品的 "类型" 产品的 "构建过程"
客户端操作 客户端只需选择工厂,直接获取产品 客户端需指定建造者,由指挥者控制步骤后获取产品
适用场景 产品类型固定,创建逻辑简单 产品复杂(多组成部分),创建步骤固定

简单总结:工厂方法是 "一步到位拿产品",建造者是 "分步操作拼产品"

相关推荐
骄马之死8 分钟前
SpringMVC + SpringBoot 核心知识点总结
java·spring boot·后端
zhengfei61120 分钟前
第3章 Agent 类型分类与设计模式
设计模式
GoGeekBaird1 小时前
Anthropic技能"(Skills)的经验分享
后端
王码码20351 小时前
多台服务器怎么统一看状态?Beszel 轻量监控,搭起来不费事
运维·服务器·后端·安全·阿里云·接口·web
刀法如飞1 小时前
一文搞懂DDD 领域驱动设计思想原理
设计模式·架构·代码规范
郑洁文2 小时前
基于Spring Boot的流浪动物救助网站
java·spring boot·后端·毕设·流浪动物救助
螺丝钉code2 小时前
JAVA项目 Claude code CLAUDE.md 到底应该怎么写
java·人工智能·claude code
指令集梦境3 小时前
Cursor + Spring Boot实战:从零写一个RESTful API
spring boot·后端·restful
摇滚侠4 小时前
Maven 入门+高深 单一架构案例 54-59
java·架构·maven·intellij-idea