go中用接口定义策略需先抽象可变行为并统一输入输出,如paymentstrategy接口仅含pay方法;运行时通过字段赋值切换策略,避免map或switch实现;初始化时须传入依赖并校验非空。

Go 里怎么用接口定义策略?
策略模式在 Go 里不靠抽象类或继承,而是靠 interface 契约。你得先想清楚:哪些行为会变?这些行为的输入输出是否一致?比如支付策略,Pay(amount float64) error 就是公共契约。
- 接口方法必须精简,只保留真正需要动态替换的部分;加多了反而让实现类负担重
- 不要为“将来可能扩展”提前加方法,等出现具体新策略再改接口(Go 崇尚小接口)
- 接口名建议用形容词或名词,比如
PaymentStrategy,别叫IPaymentStrategy(Go 不用 I 前缀)
type PaymentStrategy interface {
Pay(amount float64) error
}如何在运行时切换策略?
不是靠 new 一堆策略实例再 if-else,而是把策略当参数传、当字段存、当返回值用。核心是:策略对象本身可被赋值、替换、缓存。
- 把策略作为结构体字段声明,初始化时注入,后续直接调用
strategy.Pay() - 切换时直接赋新值:
order.Strategy = &AlipayStrategy{},不需要反射或工厂函数 - 如果策略依赖外部配置(如 API key),确保它在创建时就完成初始化,别拖到
Pay里才检查
type Order struct {
Strategy PaymentStrategy
}
<p>func (o *Order) Process(amount float64) error {
return o.Strategy.Pay(amount) // 调用当前策略
}为什么不用 map[string]func 或 switch 实现策略?
用 map[string]func 或大段 switch 看似简单,但很快会失控:
- 新增策略要改两处:注册 map 和写 func 实现,违反开闭原则
- 每个 func 都得自己处理错误、日志、重试逻辑,无法复用
- 无法携带状态(比如支付宝策略需要
appID字段,纯函数做不到) - 单元测试困难:没法 mock 一个匿名函数,但可以 mock 接口
所以宁可多写一个结构体,也别用函数表硬凑策略模式。
立即学习“go语言免费学习笔记(深入)”;
策略初始化时容易漏掉什么?
策略不是裸 struct,它往往需要依赖项。常见疏忽:
- 忘记传入必要依赖,导致
Pay运行时报nil pointer dereference - 把依赖设成全局变量,造成并发不安全(比如多个 goroutine 共享同一个 HTTP client)
- 在策略方法里做 heavy 初始化(如读配置文件),导致首次调用慢且不可控
正确做法:所有依赖通过构造函数传入,并在初始化时验证非空。
type WechatPayStrategy struct {
client *http.Client
appID string
}
<p>func NewWechatPayStrategy(client <em>http.Client, appID string) </em>WechatPayStrategy {
if client == nil {
panic("client is required")
}
return &WechatPayStrategy{client: client, appID: appID}
}策略不是写完就扔的工具,它的生命周期和业务上下文绑定越紧,越容易出错。特别是并发场景下,别让策略实例跨请求共享状态。










