如何使用Golang实现建造者模式对象组装_使用Builder Pattern组合对象

16次阅读

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

如何使用Golang实现建造者模式对象组装_使用Builder Pattern组合对象

建造者模式(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 的简洁哲学。选哪种,看你的配置维度和团队习惯。

text=ZqhQzanResources