go中建造者模式通过结构体Builder或函数式选项实现对象组装,分离构造逻辑、避免参数爆炸,支持链式调用与默认值校验。

建造者模式(Builder Pattern)在 Go 中不依赖类和继承,而是通过结构体、函数式选项和链式调用实现清晰、可扩展的对象组装。核心思路是:把对象的构造逻辑从初始化中分离出来,让调用方按需选择配置项,避免参数爆炸和不可变对象的繁琐构造。
定义目标结构体与私有字段
先设计最终要构建的对象,字段设为小写(私有),防止外部直接赋值:
例如构建一个 http 客户端配置:
type HTTPClient struct { baseURL string timeout time.Duration retries int userAgent string middleware []func(http.RoundTripper) http.RoundTripper }
所有字段都不导出,确保只能通过 Builder 控制创建过程。
立即学习“go语言免费学习笔记(深入)”;
创建 Builder 结构体并提供设置方法
Builder 是一个普通结构体,持有和目标对象相同的字段(或中间状态),每个设置方法返回 *Builder 自身,支持链式调用:
type HTTPClientBuilder struct { cfg HTTPClient } func NewHTTPClientBuilder() HTTPClientBuilder { return &HTTPClientBuilder{ cfg: HTTPClient{ timeout: 30 time.Second, retries: 3, }, } }
func (b HTTPClientBuilder) WithBaseURL(url string) HTTPClientBuilder { b.cfg.baseURL = url return b }
func (b HTTPClientBuilder) WithTimeout(d time.Duration) HTTPClientBuilder { b.cfg.timeout = d return b }
func (b HTTPClientBuilder) WithRetries(n int) HTTPClientBuilder { b.cfg.retries = n return b }
func (b HTTPClientBuilder) WithUserAgent(ua string) HTTPClientBuilder { b.cfg.userAgent = ua return b }
func (b HTTPClientBuilder) WithMiddleware(ms ...func(http.RoundTripper) http.RoundTripper) HTTPClientBuilder { b.cfg.middleware = append(b.cfg.middleware, ms...) return b }
提供 Build 方法完成最终构造
Build 方法返回不可变的目标对象(通常做一次深拷贝或只读封装)。Go 中常直接返回结构体值(值语义天然不可变):
func (b *HTTPClientBuilder) Build() HTTPClient { // 可在此校验必要字段,如: if b.cfg.baseURL == "" { panic("baseURL is required") } return b.cfg // 返回副本,调用方无法修改原始 builder 状态 }
使用示例:
client := NewHTTPClientBuilder(). WithBaseURL("https://api.example.com"). WithTimeout(10 * time.Second). WithRetries(5). WithUserAgent("MyApp/1.0"). Build()
进阶:用函数式选项(Functional Options)替代 Builder 结构体
更 Go 风格的做法是用函数类型封装配置逻辑,轻量且组合灵活:
type Option func(*HTTPClient) func WithBaseURL(url string) Option { return func(c *HTTPClient) { c.baseURL = url } }
func WithTimeout(d time.Duration) Option { return func(c *HTTPClient) { c.timeout = d } }
func NewHTTPClient(opts ...Option) HTTPClient { c := HTTPClient{ timeout: 30 * time.Second, retries: 3, } for _, opt := range opts { opt(&c) } if c.baseURL == "" { panic("baseURL is required") } return c }
调用更简洁:
client := NewHTTPClient( WithBaseURL("https://api.example.com"), WithTimeout(10 * time.Second), WithRetries(5), )
基本上就这些。Builder 模式在 Go 里不是照搬 java 写法,而是借其思想——解耦构造、提升可读性、支持默认值与校验。用结构体 Builder 适合复杂流程;用 Functional Options 更符合 Go 的简洁哲学。选哪种,看你的配置维度和团队习惯。