Go中模板方法模式用接口定义算法步骤、结构体封装固定流程,通过组合+函数字段注入可变行为;支持泛型复用,但应避免过度设计,优先选择简单函数链或选项函数。

在 Go 语言中实现模板方法模式,核心是用接口定义算法骨架,用结构体实现具体步骤,再通过组合或函数字段“注入”可变行为——因为 Go 没有继承,所以不靠子类重写,而靠组合+接口+函数值来达成相同意图。
用接口抽象步骤,结构体封装流程骨架
模板方法的本质是把不变的执行顺序(如:初始化 → 处理 → 清理)固定下来,把变化的部分(如:如何初始化、如何处理)交给实现者。Go 中可用接口描述“变化的部分”,再由某个结构体持有该接口并定义主流程:
- 定义一个接口(如 Processor),包含
Setup()、Execute()、Cleanup()等方法 - 创建一个 Workflow 结构体,它接收一个
Processor实例,并在其Run()方法中按序调用这些方法 - 不同业务逻辑只需实现 Processor 接口,无需修改
Run()流程
用函数字段替代抽象方法,更轻量灵活
如果步骤逻辑简单、不需状态共享,直接用函数类型字段更简洁。例如:
- 定义
type Step func() error - 结构体中声明
setup, execute, cleanup Step字段 -
Run()方法内依次调用:if err := w.setup(); err != nil { ... },依此类推 - 初始化时传入闭包或普通函数,比如
workflow.setup = func() error { return os.MkdirAll("tmp", 0755) }
结合泛型支持多类型流程复用(Go 1.18+)
若模板流程需适配不同输入/输出类型,可用泛型增强通用性。例如:
立即学习“go语言免费学习笔记(深入)”;
- 定义
type Workflow[T any, R any] struct { processor Processor[T, R] } - 接口
Processor[T, R]的Execute(input T) (R, error)可让同一骨架处理字符串、JSON、数据库记录等 - 实际使用时,
Workflow[string, int]{...}和Workflow[[]byte, bool]{...}共享同一个Run()实现
注意点:避免过度设计,优先考虑组合与小接口
Go 崇尚“少即是多”。模板方法不是必须的,很多场景用简单函数链或选项函数(functional options)更清晰:
- 若只有 2–3 个步骤且变化少,直接写
doSetup(); doWork(); doTeardown()更易读 - 若某步骤可能为空,接口方法应允许空实现(如返回
nil),或用指针字段 +if w.cleanup != nil判断 - 不要为模板而模板——当逻辑差异大、复用价值低时,复制粘贴几行代码,比强套模式更符合 Go 的务实风格










