策略模式属于行为型设计模式,核心思想是定义一系列算法,将每个算法封装起来,并且使它们可以相互替换,让算法的变化独立于使用算法的客户端。在Golang中,借助接口的特性可以非常优雅地实现策略模式,满足运行时动态切换算法的需求。

策略模式的核心结构
策略模式通常包含三个核心角色:
- 策略接口:定义所有支持的算法的公共接口,客户端通过该接口调用具体策略的方法。
- 具体策略:实现策略接口的具体算法类,每个类对应一种具体的算法实现。
- 上下文类:持有一个策略对象的引用,负责维护当前使用的策略,并提供设置策略、调用策略方法的能力。
Golang实现策略模式切换算法示例
下面以支付场景为例,实现不同支付方式的算法切换,支付算法包括微信支付、支付宝支付、银行卡支付三种。
1. 定义策略接口
首先定义支付策略的接口,所有具体支付算法都需要实现这个接口:
// 支付策略接口,定义支付方法
type PaymentStrategy interface {
Pay(amount float64) string
}
2. 实现具体策略
分别实现三种不同的支付算法:
// 微信支付具体策略
type WechatPay struct{}
func (w *WechatPay) Pay(amount float64) string {
return fmt.Sprintf("使用微信支付成功,支付金额:%.2f元", amount)
}
// 支付宝支付具体策略
type AliPay struct{}
func (a *AliPay) Pay(amount float64) string {
return fmt.Sprintf("使用支付宝支付成功,支付金额:%.2f元", amount)
}
// 银行卡支付具体策略
type BankCardPay struct{}
func (b *BankCardPay) Pay(amount float64) string {
return fmt.Sprintf("使用银行卡支付成功,支付金额:%.2f元", amount)
}
3. 实现上下文类
上下文类负责持有策略对象,并且提供切换策略和调用策略方法的能力:
// 支付上下文,持有当前支付策略
type PaymentContext struct {
strategy PaymentStrategy
}
// 设置支付策略
func (p *PaymentContext) SetStrategy(strategy PaymentStrategy) {
p.strategy = strategy
}
// 执行支付操作
func (p *PaymentContext) Pay(amount float64) string {
if p.strategy == nil {
return "未设置支付策略,无法完成支付"
}
return p.strategy.Pay(amount)
}
4. 客户端调用示例
在客户端中可以根据需要动态切换不同的支付算法:
package main
import "fmt"
func main() {
// 创建支付上下文
context := &PaymentContext{}
// 使用微信支付
context.SetStrategy(&WechatPay{})
result1 := context.Pay(100.50)
fmt.Println(result1)
// 切换到支付宝支付
context.SetStrategy(&AliPay{})
result2 := context.Pay(200.00)
fmt.Println(result2)
// 切换到银行卡支付
context.SetStrategy(&BankCardPay{})
result3 := context.Pay(150.75)
fmt.Println(result3)
}
策略模式的优势与适用场景
使用策略模式实现算法切换有以下明显优势:
- 避免了大量的
if-else或者switch-case条件判断代码,让代码更简洁。 - 符合开闭原则,新增算法时只需要新增具体策略类,不需要修改原有代码。
- 算法之间相互独立,修改某个算法的实现不会影响其他算法和客户端代码。
- 方便运行时动态切换算法,灵活性更高。
策略模式适合以下场景:
- 一个系统需要动态地在几种算法中选择一种。
- 一个类有多种行为,并且这些行为在运行时需要切换。
- 需要避免暴露复杂的、与算法相关的数据结构,提高代码安全性。
注意事项
在使用Golang实现策略模式时需要注意,Golang的接口是隐式实现的,不需要显式声明某个结构体实现了某个接口,只要结构体实现了接口的所有方法就自动满足接口要求,这一点让策略模式的实现更加简洁。另外如果策略数量较多,可以考虑结合工厂模式来创建具体策略对象,进一步简化客户端的调用逻辑。