

新闻资讯
技术教程Go中模板方法模式通过组合+接口+函数参数实现,核心是将可变逻辑抽为func或接口方法由调用方注入;轻量场景用函数参数,重逻辑用窄接口,横切关注用结构体钩子封装。
Go 没有继承,所谓“模板方法模式”只能靠组合 + 接口 + 函数参数模拟,核心不是复用父类骨架,而是把可变逻辑抽成 func 或接口方法,由调用方注入。
把算法中变化的部分定义为函数类型,主流程固定,变化点作为参数传入。这是最轻量、最符合 Go 习
惯的做法。
templateMethod 不依赖任何结构体,只依赖输入参数和回调函数
type OrderValidator func(*Order) error
func ProcessOrder(order *Order, validate OrderValidator) error {
if err := validate(order); err != nil {
return err
}
if err := order.Charge(); err != nil {
return err
}
return order.SendNotification()
}
当变化逻辑较重、需要复用状态或多次调用时,定义接口比裸函数更清晰。注意:接口应窄——只包含该模板真正需要的方法。
Processor、Strategy 等后缀,避免泛称 Handler
Save 或 Log),否则违反里氏替换type OrderProcessor interface {
Validate(*Order) error
Charge(*Order) error
}
func RunOrderFlow(p OrderProcessor, order *Order) error {
if err := p.Validate(order); err != nil {
return err
}
return p.Charge(order)
}
当多个模板流程共享初始化、清理、日志、重试等横切逻辑时,用结构体组合比重复写函数更可控。关键在明确“钩子”的调用时机和默认行为。
Before, After)类型统一为 func() error,便于零值安全调用Execute)不暴露内部状态,只接收必要参数type OrderTemplate struct {
Before func() error
After func() error
}
func (t *OrderTemplate) Execute(order *Order, process func(*Order) error) error {
if t.Before != nil {
if err := t.Before(); err != nil {
return err
}
}
err := process(order)
if t.After != nil {
t.After() // 忽略 after 错误,避免掩盖主流程错误
}
return err
}
真正难的不是写模板,而是判断哪部分该抽象、哪部分该固化。业务规则常变,但数据流向和错误处理路径往往稳定;优先抽象的是“做什么”,而不是“怎么做”。