第 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. 与工厂方法模式的核心区别

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

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

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

相关推荐
一直_在路上3 小时前
Go语言在医疗IT中的MySQL高可用集群架构实践:从选型到百万QPS
后端
我不是混子3 小时前
MySQL中如何查看数据库容量大小、表容量大小、索引容量大小?
后端·mysql
似水流年流不尽思念3 小时前
Redis 如何配置 Key 的过期时间?它的实现原理?
后端
Coding_Doggy3 小时前
java面试day3 | 框架篇、Spring、SpringMVC、SpringBoot、MyBatis、注解、AOP、Bean
java·mysql·面试
yunxi_053 小时前
RAG 项目中的向量化实战:让模型精准检索上传文档
后端·ai编程
程序员小富3 小时前
字节二面挂!面试官: Redis 内存淘汰策略 LRU 和传统 LRU 差异,我答懵了
后端
万粉变现经纪人3 小时前
如何解决 pip install 安装报错 ModuleNotFoundError: No module named ‘django’ 问题
ide·后端·python·django·beautifulsoup·pandas·pip
new_daimond3 小时前
设计模式详解:单例模式、工厂方法模式、抽象工厂模式
单例模式·设计模式·工厂方法模式
Li zlun3 小时前
Kubernetes 进阶实战:CRD、Gateway API 与优先级调度
java·kubernetes·gateway