go中高可复用接口设计的核心是控制抽象粒度、约束实现边界、避免过度封装;接口要窄、组合显式、优先用函数、错误分层处理、导出接口需谨慎。

Go 里没有继承,所谓“高可复用接口设计”,核心不是套模式,而是控制抽象粒度、约束实现边界、避免过度封装。
接口定义要窄:只暴露模板真正需要的方法
宽接口(比如 Handler、Service)容易让实现者被迫实现无关逻辑,破坏复用前提。模板方法中真正被调用的,就那几个步骤——只把它们拎出来定义接口。
- 错误写法:
type OrderService interface { Validate() error; Charge() error; Notify() error; Save() error; Log() string }——Save和Log不参与流程骨架,却强制实现 - 正确写法:
type OrderProcessor interface { Validate(*Order) error; Charge(*Order) error }——RunOrderFlow只依赖这两个方法,其余由外部或钩子处理 - 接口名带语义后缀,如
Validator、Exporter、RetryPolicy,一眼可知用途
组合比嵌套更可控:用结构体封装流程+注入接口
别写 type RegisterFlow struct{ Workflow } 这种隐式嵌入,它会让调用方误以为能直接访问 Workflow 字段,破坏封装。显式组合才是 Go 风格。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
- 定义模板结构体时,字段用小写:
workflow Workflow,不导出 -
Execute()方法内部只调用t.workflow.Step1()等,不暴露t.workflow给外部 - 构造函数接收接口值:
NewTemplate(w Workflow) *Template,而非具体类型 - 若需扩展行为(如日志开关),加一个
shouldLog func() bool字段,而不是塞进接口
函数参数比接口更轻量:简单变化点优先用 func
当差异逻辑是单次、无状态、不共享内部字段时,传 func(*Order) error 比定义新接口更干净。
- 例如渠道校验:
ProcessOrder(order, alipayValidator)和ProcessOrder(order, wechatValidator)直接传函数,不用为每个渠道建 struct - 避免为一行逻辑定义类型:
type Validator func(...)就够了,不必再写type AlipayValidator struct{}+ 实现接口 - 函数签名保持一致,便于测试替换:
var mockValidator = func(o *Order) error { return nil }
错误处理必须分层:接口方法返回 error,但不透出底层细节
复用的前提是上层能区分错误类型并做针对性处理。如果所有实现都返回 fmt.Errorf("db failed: %w", err),调用方只能全盘重试或降级。
- 定义业务错误类型,如
ErrInsufficientBalance、ErrInvalidChannel,在接口方法中直接返回 - 实现类内部用
errors.Is(err, sql.ErrNoRows)判断并转成业务错误,不把sql.ErrNoRows向上传 - 模板方法不处理 error,只传递:
if err := t.workflow.Step1(); err != nil { return err }
最容易被忽略的是:接口一旦导出,就很难改。宁可多定义几个窄接口,也不要试图靠一个大接口撑起所有场景。复用性不是靠“一次定义到处用”实现的,而是靠“按需抽取、精准约束”换来的。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










