golang中“建造者+工厂”组合模式将创建逻辑分层:工厂决定类型并返回建造者,建造者链式配置后Build()生成对象,适用于http客户端等复杂初始化场景。

用 golang 实现“建造者 + 工厂”组合模式,核心是把对象的构造逻辑分层:工厂负责决定创建哪一类对象,建造者负责按需组装复杂结构。这种方式特别适合配置项多、变体多、初始化步骤繁琐的场景(比如 HTTP 客户端、数据库连接池、消息生产者等)。
工厂决定类型,建造者负责细节
工厂不直接 new 结构体,而是返回一个建造者实例;建造者提供链式方法设置字段,最后调用 Build() 得到最终对象。这样既解耦了创建逻辑,又避免了构造函数参数爆炸。
例如要支持多种日志输出器(ConsoleLogger、FileLogger、RemoteLogger),每种又有不同配置(级别、格式、缓冲区大小等):
- 定义统一接口:
type Logger Interface { Log(msg String) } - 为每种实现定义专属建造者(如
ConsoleLoggerBuilder),含私有字段和链式设置方法(WithLevel(),WithFormat()) - 工厂函数根据输入返回对应建造者:
func NewLoggerBuilder(kind string) LoggerBuilder
用泛型提升建造者复用性(Go 1.18+)
若多个类型构造流程相似(比如都有 name、timeout、retry),可抽象出泛型建造者基类:
立即学习“go语言免费学习笔记(深入)”;
type Builder[T any] interface { Build() T } type GenericBuilder[T any] struct { value T }
func (b GenericBuilder[T]) SetField(field func(T) T) GenericBuilder[T] { b.value = field(b.value) return b }
再为具体类型嵌入该结构,复用通用设置逻辑,同时保留类型安全。
避免常见陷阱
建造者应是**不可变设计**:每次设置都返回新实例,或确保内部状态不会被外部意外修改(如深拷贝切片、避免暴露指针字段)。工厂返回的建造者也应是值类型或带副本语义,防止并发下状态污染。
- 不要让建造者暴露未完成的中间状态(如
Build()前字段可被随意读取) - 在
Build()中做必要校验(如必填字段是否为空),失败时 panic 或返回 Error(推荐后者) - 工厂函数名建议体现意图,如
NewHTTPClientBuilder()比NewBuilder()更清晰
实际调用示例简洁直观
使用者无需关心内部结构,只管“选类型 → 配置 → 构建”:
logger := NewLoggerBuilder("file"). WithLevel("debug"). WithFilePath("/var/log/app.log"). WithBufferSize(4096). Build() client := NewHTTPClientBuilder(). WithTimeout(30 * time.Second). WithRetry(3). WithMiddleware(AuthMiddleware, TraceMiddleware). Build()
这种写法语义明确、易扩展、测试友好——每个建造者可单独单元测试,工厂可轻松新增类型而不改调用方代码。