策略模式 (Strategy Pattern)

意图

策略模式是一种行为型设计模式,它定义了一系列算法,将每个算法封装起来,并使它们可以互换。策略模式让算法的变化独立于使用算法的客户,从而简化了算法的管理和扩展。

问题

在现实世界中,考虑一个支付系统,不同的支付方式(如信用卡、支付宝、PayPal)需要不同的处理逻辑。如果将所有支付逻辑都写在一个类中,会导致类变得复杂且难以维护。策略模式通过将不同的支付方式封装为不同的策略对象,并在运行时选择合适的策略,简化了支付逻辑的管理。

解决方案

使用策略模式,我们可以定义一个策略接口,声明算法的方法。然后,创建具体策略类来实现这些方法。上下文类(Context)持有一个策略对象,并在运行时委托给策略对象来执行算法。通过改变策略对象,可以在运行时改变上下文的行为。

模式结构

  1. 策略接口(Strategy):定义算法的方法。
  2. 具体策略(Concrete Strategy):实现策略接口,定义具体的算法。
  3. 上下文(Context):持有策略对象,并将算法的执行委托给策略对象。

代码

以下是使用Go语言实现的策略模式示例:

package main

import "fmt"

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

// 具体策略 - 信用卡支付
type CreditCardPayment struct {
    cardNumber string
}

func (c *CreditCardPayment) Pay(amount float64) {
    fmt.Printf("使用信用卡 %s 支付 %.2f 元\n", c.cardNumber, amount)
}

// 具体策略 - 支付宝支付
type AlipayPayment struct {
    account string
}

func (a *AlipayPayment) Pay(amount float64) {
    fmt.Printf("使用支付宝账户 %s 支付 %.2f 元\n", a.account, amount)
}

// 具体策略 - PayPal支付
type PayPalPayment struct {
    email string
}

func (p *PayPalPayment) Pay(amount float64) {
    fmt.Printf("使用PayPal账户 %s 支付 %.2f 元\n", p.email, amount)
}

// 上下文 - 支付处理
type PaymentContext struct {
    strategy PaymentStrategy
}

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

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

func main() {
    // 创建支付上下文
    paymentContext := &PaymentContext{}

    // 使用信用卡支付
    paymentContext.SetStrategy(&CreditCardPayment{cardNumber: "1234-5678-9876-5432"})
    paymentContext.ExecutePayment(100.50)

    // 使用支付宝支付
    paymentContext.SetStrategy(&AlipayPayment{account: "example@alipay.com"})
    paymentContext.ExecutePayment(200.75)

    // 使用PayPal支付
    paymentContext.SetStrategy(&PayPalPayment{email: "example@paypal.com"})
    paymentContext.ExecutePayment(300.00)
}

适用场景

  • 当需要定义一系列算法,并使它们可以互换时,例如在支付系统中选择不同的支付方式。
  • 当算法的使用场景多变,且需要在运行时动态选择不同的算法时。
  • 当算法的实现复杂,而希望将其封装在不同的策略对象中,从而提高系统的可维护性时。

实现方式

  1. 定义策略接口,声明算法的方法。
  2. 创建具体策略类,分别实现策略接口中的方法,定义具体的算法实现。
  3. 定义上下文类,持有策略对象,并将算法的执行委托给策略对象。
  4. 客户端代码创建上下文对象和具体策略对象,并设置合适的策略对象来执行算法。

优缺点

优点

  • 策略模式将不同的算法封装到不同的策略对象中,使得算法的管理和扩展变得更加灵活和可维护。
  • 客户端代码可以在运行时动态选择不同的策略,而不需要修改上下文类。
  • 避免了大量的条件语句,使得代码更加简洁。

缺点

  • 可能会引入大量的策略类,增加了系统的复杂性。
  • 上下文类与策略类之间的依赖关系可能会导致额外的复杂性。

其他模式的关系

  • 策略模式与状态模式(State Pattern):状态模式用于管理对象的状态并改变其行为,而策略模式用于将算法封装在不同的策略对象中。两者可以结合使用,例如在状态模式中使用策略模式来定义不同状态下的行为。
  • 策略模式与工厂模式(Factory Pattern):工厂模式用于创建对象,而策略模式用于封装算法并使其可以互换。可以结合使用,例如使用工厂模式创建策略对象并在策略模式中使用。
  • 策略模式与命令模式(Command Pattern):命令模式用于封装请求的操作,而策略模式用于封装不同的算法。可以结合使用,例如在策略模式中使用命令模式来执行策略操作。