如何使用Golang实现策略模式_Golang策略模式业务逻辑封装方法

17次阅读

go语言策略模式推荐三种实现:1. 简单无状态用函数类型;2. 带状态依赖用接口+结构体;3. 可扩展查找用map注册表,需注意错误统一、context透传与并发安全。

如何使用Golang实现策略模式_Golang策略模式业务逻辑封装方法

Go 语言没有类继承和接口实现的强制约束,策略模式不能照搬 java/C# 那套写法;它更适合用函数类型、接口+结构体组合、或 map[String]func 的轻量方式来封装业务逻辑。

func 类型定义策略最简洁

当策略逻辑简单、无状态、不需复用内部字段时,直接用函数类型是最自然的选择。比如支付方式:微信支付、支付宝、银行卡,各自只需一个 Pay(amount float64) Error 行为。

定义统一策略类型:

type PayStrategy func(amount float64) error

实现不同策略:

立即学习go语言免费学习笔记(深入)”;

var WechatPay PayStrategy = func(amount float64) error {     fmt.Println("WeChat pay:", amount)     return nil } 

var Alipay PayStrategy = func(amount float64) error { fmt.Println("Alipay:", amount) return nil }

使用时直接传入函数值,无需实例化结构体:

func DoPayment(strategy PayStrategy, amount float64) error {     return strategy(amount) } 

DoPayment(WechatPay, 99.9)

⚠️ 注意:这种写法无法在策略内部访问上下文(如用户 ID、订单号),也不便于加日志/监控中间件——需要升级为接口方式。

用接口 + 结构体实现带状态的策略

当策略需要持有配置、依赖外部服务(如调用某个 *http.Client数据库连接),就该用接口定义行为,结构体承载状态。

定义接口:

type PaymentProcessor interface {     Process(orderID string, amount float64) error }

实现微信支付策略:

type WechatProcessor struct {     client *http.Client     appID  string } 

func (w *WechatProcessor) Process(orderID string, amount float64) error { // 使用 w.client 和 w.appID 发起请求 fmt.Printf("WeChat processing %s for %.2fn", orderID, amount) return nil }

工厂函数按需返回具体策略:

func NewPaymentProcessor(kind string, cfg Config) PaymentProcessor {     switch kind {     case "wechat":         return &WechatProcessor{client: &http.Client{}, appID: cfg.AppID}     case "alipay":         return &AlipayProcessor{gateway: cfg.AlipayURL}     default:         panic("unknown processor")     } }

✅ 这种方式支持依赖注入、单元测试 mock、运行时动态切换,是中大型业务推荐的写法。

map[string]PaymentProcessor 实现策略注册与查找

避免每次 if-else 或 switch 判断类型,把策略实例缓存起来,按 key 查找更清晰、可扩展性更强。

初始化全局策略注册表

var processors = make(map[string]PaymentProcessor) 

func RegisterProcessor(name string, p PaymentProcessor) { processors[name] = p }

func GetProcessor(name string) (PaymentProcessor, bool) { p, ok := processors[name] return p, ok }

注册时:

RegisterProcessor("wechat", &WechatProcessor{...}) RegisterProcessor("alipay", &AlipayProcessor{...})

使用时:

if p, ok := GetProcessor("wechat"); ok {     p.Process("ORD-123", 199.0) }

⚠️ 注意:注册时机必须早于首次使用(通常放在 init() 或应用启动时);并发读写需加 sync.RWMutex(如果运行时会动态增删策略)。

策略切换时容易忽略的两个点

一是错误处理一致性:不同策略可能返回不同格式的错误(如网络超时 vs 参数校验失败),建议统一封装成自定义错误类型,带 Code() 方法便于上层分类响应。

二是上下文传递:别把 context.Context编码进接口方法签名里——应该让所有策略方法都接收 ctx context.Context,否则超时控制、trace 透传都会断掉。

例如接口应定义为:

type PaymentProcessor interface {     Process(ctx context.Context, orderID string, amount float64) error }

不是所有策略都需要用到 ctx,但留着它,比后面补加更安全。

text=ZqhQzanResources