Skip to content

建造者模式

建造者模式用于分步骤构建复杂对象,把对象的创建过程和对象本身分开。它适合构造参数多、可选字段多、校验规则多、对象希望不可变的场景。

常见场景:HTTP 请求对象、导出任务配置、报表查询条件、消息发送命令、复杂 DTO、Lombok @Builder、MyBatis/Spring 中大量配置类。

为什么需要建造者

假设要创建一个导出任务:

java
ExportTask task = new ExportTask(
    "asset",
    "资产台账",
    "xlsx",
    true,
    true,
    10000,
    LocalDateTime.now(),
    "admin"
);

这种长构造器有几个问题:

问题后果
参数太多调用方不知道每个位置代表什么
多个同类型参数字符串、布尔值容易传反
可选参数多构造器重载爆炸
校验分散对象可能处于非法状态
创建过程不表达业务含义读代码时难理解

建造者用链式方法表达字段含义,并在 build 时统一校验。

总体流程

mermaid
flowchart TD
    A["创建 Builder"] --> B["设置必要字段"]
    B --> C["设置可选字段"]
    C --> D["build 统一校验"]
    D --> E["创建不可变对象"]

Java Demo:导出任务建造者

目标对象:

java
public class ExportTask {
    private final String bizType;
    private final String fileName;
    private final String fileType;
    private final boolean includeHeader;
    private final int maxRows;
    private final String operator;

    private ExportTask(Builder builder) {
        this.bizType = builder.bizType;
        this.fileName = builder.fileName;
        this.fileType = builder.fileType;
        this.includeHeader = builder.includeHeader;
        this.maxRows = builder.maxRows;
        this.operator = builder.operator;
    }

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

    public static class Builder {
        private String bizType;
        private String fileName;
        private String fileType = "xlsx";
        private boolean includeHeader = true;
        private int maxRows = 10000;
        private String operator;

        public Builder bizType(String bizType) {
            this.bizType = bizType;
            return this;
        }

        public Builder fileName(String fileName) {
            this.fileName = fileName;
            return this;
        }

        public Builder fileType(String fileType) {
            this.fileType = fileType;
            return this;
        }

        public Builder includeHeader(boolean includeHeader) {
            this.includeHeader = includeHeader;
            return this;
        }

        public Builder maxRows(int maxRows) {
            this.maxRows = maxRows;
            return this;
        }

        public Builder operator(String operator) {
            this.operator = operator;
            return this;
        }

        public ExportTask build() {
            if (bizType == null || bizType.isBlank()) {
                throw new IllegalArgumentException("业务类型不能为空");
            }
            if (fileName == null || fileName.isBlank()) {
                throw new IllegalArgumentException("文件名不能为空");
            }
            if (maxRows <= 0 || maxRows > 100000) {
                throw new IllegalArgumentException("导出行数不合法");
            }
            return new ExportTask(this);
        }
    }
}

调用:

java
ExportTask task = ExportTask.builder()
        .bizType("asset")
        .fileName("资产台账")
        .fileType("xlsx")
        .includeHeader(true)
        .maxRows(50000)
        .operator("admin")
        .build();

读起来比长构造器清楚很多。

建造者解决的不是 new,而是复杂构建过程

如果对象只有两三个字段:

java
new User(id, name);

没必要上建造者。

建造者适合:

  1. 参数多。
  2. 可选字段多。
  3. 默认值多。
  4. 构建前要校验。
  5. 希望对象不可变。
  6. 构建步骤要表达业务含义。

和工厂模式区别

对比建造者模式工厂模式
关注点一个复杂对象如何一步步构建根据条件创建哪个对象
结果通常是一类对象可能是多个实现类之一
适合参数多、构建过程复杂创建逻辑变化、隐藏具体实现
例子构建导出任务配置根据支付类型获取支付服务

工厂解决“创建哪个”,建造者解决“怎么构建完整对象”。

Lombok @Builder

很多项目用 Lombok:

java
@Builder
public class ExportTask {
    private String bizType;
    private String fileName;
    private String fileType;
}

调用:

java
ExportTask task = ExportTask.builder()
        .bizType("asset")
        .fileName("资产台账")
        .fileType("xlsx")
        .build();

注意:Lombok 只是生成 Builder 代码,不自动保证业务合法性。必要校验仍然要放在构造方法、静态工厂、build 扩展或 Service 中。

商业场景

医疗资产导出任务:

  1. 导出业务类型。
  2. 查询条件。
  3. 文件格式。
  4. 最大行数。
  5. 是否脱敏。
  6. 操作人。
  7. 回调地址。

这些字段既多又有默认值和校验,适合建造者。这样可以避免到处传 Map<String, Object>,也避免长构造器。

常见坑

问题后果建议
简单对象也用 Builder代码变长字段少时直接构造
Builder 不校验构造出非法对象build 时统一校验
滥用 Map 代替 Builder类型不安全明确定义字段
Builder 对象复用上一次字段污染下一次Builder 用完即丢
Lombok 后忽略不可变性对象仍可被随意改配合 final、私有构造、无 setter

面试标准回答

text
建造者模式用于分步骤构建复杂对象,适合参数多、可选字段多、默认值多、需要统一校验或不可变对象的场景。它能避免长构造器和构造器重载爆炸,让创建过程更清晰。和工厂模式相比,工厂关注创建哪个对象,建造者关注一个复杂对象如何构建。简单对象不需要 Builder,过度使用会增加代码量。

本章小结

建造者模式的核心是“让复杂对象创建过程可读、可控、可校验”。它不是为了让 new 看起来高级,而是当构造过程真的复杂时,把参数、默认值、校验和不可变性集中管理。