Skip to content

在 Go 中,策略模式(Strategy Pattern)是一种行为设计模式,它通过定义一系列算法,将每种算法封装在独立的类中,并使它们可以互相替换。这种模式使算法能够独立于使用它们的客户端而变化。

由于 Go 是静态类型的语言,但也支持接口,这使得策略模式能够通过接口来实现。以下是策略模式在 Go 中的详细说明和示例。


策略模式的核心

  1. Context(上下文): 保存对具体策略对象的引用,并提供对外的操作接口。
  2. Strategy(策略接口): 定义所有支持的算法或策略。
  3. ConcreteStrategy(具体策略): 实现策略接口的具体算法。

Golang 中策略模式实现

示例:支付策略模式

我们通过一个支付系统的例子来说明策略模式。假设我们支持不同的支付方式(信用卡、PayPal 和现金),需要在运行时动态选择支付策略。

go
package main

import "fmt"

// Strategy 定义策略接口
type PaymentStrategy interface {
	Pay(amount float64)
}

// ConcreteStrategy: 信用卡支付
type CreditCardPayment struct {
	cardNumber string
}

func (cc *CreditCardPayment) Pay(amount float64) {
	fmt.Printf("Paid %.2f using Credit Card (%s).\n", amount, cc.cardNumber)
}

// ConcreteStrategy: PayPal 支付
type PayPalPayment struct {
	email string
}

func (pp *PayPalPayment) Pay(amount float64) {
	fmt.Printf("Paid %.2f using PayPal (%s).\n", amount, pp.email)
}

// ConcreteStrategy: 现金支付
type CashPayment struct{}

func (cp *CashPayment) Pay(amount float64) {
	fmt.Printf("Paid %.2f using Cash.\n", amount)
}

// Context: 支付上下文
type PaymentContext struct {
	strategy PaymentStrategy
}

func (pc *PaymentContext) SetStrategy(strategy PaymentStrategy) {
	pc.strategy = strategy
}

func (pc *PaymentContext) Pay(amount float64) {
	pc.strategy.Pay(amount)
}

// 测试代码
func main() {
	// 创建支付上下文
	context := &PaymentContext{}

	// 使用信用卡支付
	context.SetStrategy(&CreditCardPayment{cardNumber: "1234-5678-9012-3456"})
	context.Pay(100.0)

	// 使用 PayPal 支付
	context.SetStrategy(&PayPalPayment{email: "user@example.com"})
	context.Pay(200.0)

	// 使用现金支付
	context.SetStrategy(&CashPayment{})
	context.Pay(50.0)
}

核心逻辑分解

  1. 定义策略接口(PaymentStrategy): 定义了所有支付方式需要实现的 Pay 方法。
  2. 实现具体策略(CreditCardPayment, PayPalPayment, CashPayment): 不同支付方式实现自己的 Pay 方法。
  3. 上下文(PaymentContext): 提供 SetStrategy 方法,用于动态设置策略。

策略模式的优点

  1. 遵循开闭原则:
    • 添加新的支付方式时,只需添加一个新的策略类,而无需修改现有代码。
  2. 提高代码复用性:
    • 每种策略实现是独立的,可以在其他地方复用。
  3. 提高代码可读性和灵活性:
    • 客户端可以在运行时动态切换策略。

策略模式的实际应用

  1. 日志系统: 根据运行环境选择不同的日志策略(例如控制台日志、文件日志、远程日志)。
  2. 压缩算法: 动态选择压缩策略(如 gzip、zlib 或无压缩)。
  3. 排序算法: 动态选择不同排序方式(如快速排序、归并排序等)。
  4. 路由策略: 根据不同网络条件选择不同的路由算法。

扩展: 策略模式与匿名函数结合

在 Go 中,可以直接使用函数作为策略,而不需要定义独立的策略结构体。这使策略模式更加简洁。

示例:排序策略模式

go
package main

import (
	"fmt"
	"sort"
)

type SortStrategy func([]int)

func AscendingSort(arr []int) {
	sort.Ints(arr)
	fmt.Println("Sorted in Ascending Order:", arr)
}

func DescendingSort(arr []int) {
	sort.Sort(sort.Reverse(sort.IntSlice(arr)))
	fmt.Println("Sorted in Descending Order:", arr)
}

type SortContext struct {
	strategy SortStrategy
}

func (sc *SortContext) SetStrategy(strategy SortStrategy) {
	sc.strategy = strategy
}

func (sc *SortContext) Sort(arr []int) {
	sc.strategy(arr)
}

func main() {
	data := []int{5, 2, 8, 1, 3}
	context := &SortContext{}

	// 使用升序排序策略
	context.SetStrategy(AscendingSort)
	context.Sort(data)

	// 使用降序排序策略
	context.SetStrategy(DescendingSort)
	context.Sort(data)
}

通过函数实现策略模式,减少了定义接口和结构体的复杂性,非常适合小型项目和快速原型开发。

希望这些示例和分析对你理解 Go 的策略模式有所帮助!如果还有问题,可以继续讨论~ 😊