建造者模式适用于字段多、可选字段多、需默认值管理、统一校验及不可变性的复杂对象构建。它通过链式调用提升可读性,延迟校验至Build()阶段,支持不可变对象创建与子类型复用,但简单对象无需使用。
当一个结构体有 5 个以上字段,其中 2–3 个是可选的(比如 ServerConfig 的 CertFile、EnableTLS、Middlewares),直接用结构体字面量初始化会频繁出现零值或 nil 占位,阅读和维护困难。建造者模式把字段设置拆成链式方法调用,让意图一目了然。
NewXxx() 变体&ServerConfig{Host: "x", Port: 8080, ...} 这类易错长表达式Port: 8080、ReadTimeout: 5 * time.Second)放在 NewServerConfigBuilder() 里,而非散落在各处有些字段之间存在约束关系,比如 EnableTLS == tru 时必须提供
eCertFile 和 KeyFile;又或者端口必须在 1–65535 范围内。这些逻辑不适合塞进每个 setter 方法里,而应延迟到 Build() 阶段一次性检查。
Build() 是唯一出口,天然适合集中做参数合法性校验(*T, error),比构造后才发现问题更早暴露Port: 0 却没被发现,直到运行时报错)很多配置类对象一旦创建就不该被修改(比如 HTTP server 启动后禁止动态改 Host)。建造者模式天然支持“构建即冻结”——Build() 返回的是只读副本或不暴露字段的结构体指针,外部无法再修改内部状态。
Build() 应返回深拷贝(尤其含切片、map、指针字段时)b.config(如示例中那样),则外部仍可能通过引用修改原值,这是常见疏漏当需要基于同一套步骤(如“设置主机→设端口→加中间件→启用安全”)但产出不同具体类型(*HTTPServerConfig / *GRPCServerConfig),可以抽象出 Builder 接口,由不同 concrete builder 实现细节。
SetupCommonSteps(b Builder)
建造者模式不是银弹。字段少、无默认值、无校验需求的对象(比如只有 Name 和 ID 的 User)硬套 builder 反而啰嗦。关键在“复杂性是否真的存在”——参数爆炸、校验耦合、不可变诉求,三者占其一,就值得引入。