跳至正文
来两杯美式
返回

设计模式之建造者模式:复杂对象的组装艺术

By 来两杯美式
发布于

这是 2020 年 3 月整理的设计模式专题第二篇。建造者模式是面试常客,尤其是”建造者和工厂有什么区别”这个问题。本文从定义出发,用 Computer 的链式 Builder 示例讲清实现,再深入对比它与工厂模式的本质差异。

简单说明

建造者模式(Builder Pattern):将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示

工厂模式:  工厂 ——> 直接返回完整产品(固定配方)
建造者:    指挥者 ——> 一步步"指挥"建造者 ——> 按需组装出产品(可定制配方)

经典实现

经典实现说明
StringBuilder链式 append 组装字符串,最终 toString 输出
Lombok @Builder注解自动生成 Builder 内部类
Guava cacheCacheBuilder 链式配置构建缓存实例

简单代码示例

@Data
@AllArgsConstructor
public class Computer {

    private String cpu;
    private String gpu;
    private String memory;

    public static ComputerBuilder builder() {
        return new ComputerBuilder();
    }

    public static class ComputerBuilder {
        private String cpu;
        private String gpu;
        private String memory;

        public ComputerBuilder cpu(String cpu) {
            this.cpu = cpu;
            return this;
        }

        public ComputerBuilder gpu(String gpu) {
            this.gpu = gpu;
            return this;
        }

        public ComputerBuilder memory(String memory) {
            this.memory = memory;
            return this;
        }

        public Computer build() {
            return new Computer(cpu, gpu, memory);
        }
    }
}

使用:

Computer computer = Computer.builder()
        .cpu("i7-9700K")
        .gpu("RTX 2080")
        .memory("16G")
        .build();

链式调用的秘密:每个 setter 方法返回 this(建造者自身),所以可以一路 .cpu().gpu().memory() 连写;最后的 build() 才真正创建产品对象。

为什么要用建造者模式

没有建造者时,复杂对象的创建通常面临两个困境:

困境一:构造器参数爆炸

// 6 个参数的构造器,调用时根本分不清谁是谁
new Computer("i7-9700K", "RTX 2080", "16G", "512G SSD", "Wi-Fi 6", "机械键盘");

困境二:可选项与不可变对象冲突

// JavaBean 风格:可读性差,且对象是可变的(中途可能被改)
Computer c = new Computer();
c.setCpu("i7-9700K");
c.setGpu("RTX 2080");   // 如果忘了 set memory,对象就不完整

建造者的解法:字段只在 build() 时一次性组装进产品,产品本身可以设计成不可变对象;同时每个字段通过语义化方法名(.cpu().gpu())显式赋值,可读性远超长构造器

GoF 经典角色

完整的建造者模式包含四个角色:

角色职责Computer 示例中的对应
Product(产品)被构建的复杂对象Computer
Builder(抽象建造者)声明构建各部件的方法ComputerBuilder 的方法集合
ConcreteBuilder(具体建造者)实现各部件的具体构建逻辑ComputerBuilder
Director(指挥者)定义构建步骤与顺序本例中由客户端直接链式调用充当

什么时候需要 Director:当构建步骤有固定顺序(比如必须先装 CPU 才能装内存)且顺序被多处复用时,抽出 Director 统一编排;如果只是简单的可选字段组装,客户端链式调用即可,Director 可省略。

public class ComputerDirector {
    private Computer.ComputerBuilder builder;

    public ComputerDirector(Computer.ComputerBuilder builder) {
        this.builder = builder;
    }

    // 固定的组装流程:CPU → 内存 → GPU
    public Computer constructGamingPC() {
        return builder.cpu("i7").memory("16G").gpu("RTX 2080").build();
    }

    public Computer constructOfficePC() {
        return builder.cpu("i3").memory("8G").gpu("核显").build();
    }
}

建造者 vs 工厂

对比项工厂模式建造者模式
关注点创建什么产品如何一步步组装产品
产品形态创建的产品是一致的(同一种类)按调用顺序/部件不同,可创建不同的表示
创建粒度一步创建,直接返回分步构建,最后 build()
适用场景产品种类多、创建逻辑相似对象构造复杂、参数多、有可选字段
典型实现Calendar、Spring BeanFactoryStringBuilder、Lombok @Builder

一句话区分:工厂模式”造什么”,建造者模式”怎么造”

使用场景与优缺点

适用场景

优点

缺点

小结


分享这篇文章:
通过邮件分享这篇文章✓ 链接已复制
查看系列全部文章
  1. 01.软件设计原则:SOLID + KISS / YAGNI / LOD 全景
  2. 02.设计模式之原型模式,及深浅拷贝
  3. 03.设计模式之工厂模式:简单工厂、工厂方法与抽象工厂
  4. 04.设计模式之建造者模式:复杂对象的组装艺术
  5. 05.设计模式之适配器模式:让不兼容的接口协同工作
  6. 06.设计模式之桥接模式:抽象与实现分离,各自独立变化
  7. 07.设计模式之装饰者模式:动态增强,比继承更有弹性
  8. 08.设计模式之代理模式:静态代理与 JDK 动态代理
  9. 09.设计模式之外观模式:统一门面,简化子系统调用
  10. 10.设计模式之享元模式:共享细粒度对象,降低内存占用
  11. 11.设计模式之策略模式:算法家族,自由切换
  12. 12.设计模式之模板方法模式:固定骨架,可变步骤
  13. 13.设计模式之观察者模式:一对多依赖,状态变更自动通知
  14. 14.设计模式之责任链模式:请求逐级传递,动态组合处理者
  15. 15.设计模式之状态模式:状态变,行为变
  16. 16.设计模式之迭代器模式:不暴露内部实现,顺序访问集合

上一篇
TCP 与 UDP:三次握手、四次挥手、SYN 攻击与选型
下一篇
DDD 复杂业务系统设计(五):聚合与聚合根,一个“选课单”应该装多少东西