go策略模式核心在于接口契约干净、依赖注入安全、运行时切换并发安全;接口仅含纯行为方法,构造函数校验依赖,策略字段需rwmutex保护,注册表替代if-else硬编码。

Go 语言策略模式不是“写个接口+几个 struct”就完事的,核心在于接口契约是否干净、依赖注入是否安全、运行时切换是否并发安全——这三处错一个,轻则 panic,重则线上数据错乱。
策略接口只该有 Pay()、Sort()、Route() 这类纯行为方法
接口里塞 Init()、Close()、SetLogger() 是典型错误。这些属于生命周期或依赖管理,和“算法怎么做”无关。比如支付策略,PaymentStrategy 接口只该有 Pay(amount float64) error;排序策略只该有 Sort([]int) []int。
- 方法名必须导出(首字母大写),否则其他包无法实现
- 别提前加
ctx context.Context参数,等真要超时控制时再扩接口 - 拒绝
interface{}或map[string]interface{}当策略类型,编译期没检查,运行时断言失败直接 panic - 接口越小越好,Go 崇尚“小接口、多组合”,不是“大接口、全实现”
具体策略必须用 NewXXX 构造函数初始化并校验依赖
裸 struct{ client *http.Client } 不是策略,是隐患。它没做非空检查,也没把依赖关系显式暴露出来。
- 构造函数统一用
NewAlipay(client *alipay.Client, logger *log.Logger)这种命名,返回接口类型(如PaymentStrategy) - 内部必须检查关键依赖是否为 nil,比如
if client == nil { panic("client is required") } - 别在
Pay()方法里现场建 HTTP 连接或读配置文件,延迟不可控,且每次调用都重复初始化 - 如果初始化可能失败(如密钥解析失败),返回
(PaymentStrategy, error),不 panic
运行时切换策略必须封装在结构体字段里,并用 sync.RWMutex 保护
用全局变量 var currentStrategy PaymentStrategy + SetStrategy() 是高危操作。多个 goroutine 同时写会触发 Go runtime 的 data race 检测,直接 crash。
- 正确做法是把策略作为服务结构体的字段,例如
type PaymentService struct { mu sync.RWMutex; stra PaymentStrategy } -
SetStrategy()走mu.Lock(),Process()走mu.RLock()—— 读多写少场景下比sync.Mutex更高效 - 如果策略启动后就固定(比如从配置加载一次),用
sync.Once初始化即可,不用锁 - 绝对不要在 HTTP handler 里直接改全局策略变量,一个请求改了,所有后续请求都跟着变
动态路由别用 if-else 硬编码,注册表 + 工厂函数才是可维护方案
写 if order.Type == "vip" { useVIPStrategy() } 看似简单,但每新增一种策略就要改两处:注册逻辑 + if 分支。很快失控。
- 用
map[string]func() PaymentStrategy注册工厂函数,键是策略标识(如"alipay"),值是构造函数闭包 - 根据业务参数(用户等级、订单类型、地区)查表获取构造函数,再调用生成实例
- 注册表初始化放在
init()或启动时,避免运行时反复 map 查找影响性能 - 注册表本身可以加一层包装,支持按条件 fallback(比如 VIP 用户降级走普通策略)
最容易被忽略的是:策略对象是否真的无状态。如果有缓存、计数器、连接池等内部状态,多个 goroutine 共享同一个策略实例时,必须自己保证线程安全——RWMutex 只保护字段赋值,不保护策略内部逻辑。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











