策略模式(Strategy Pattern)是一种行为型设计模式,它允许在运行时选择算法的行为,并将其封装在一个指定的算法类中。这种模式可以使得算法的选择独立于使用它的客户代码。
应用场景
当需要在运行时选择不同的算法时,可以使用策略模式。在以下场景中,策略模式特别有用:
- 当类中有许多与某个行为相关的条件语句时;
- 当需要在不影响其他代码的情况下轻松更改算法时;
- 当类中有许多if-else语句时,应该使用这个模式。
实现
在实现策略模式时,需要考虑以下角色:
- Context: 上下文,包含策略的引用并且执行与策略关联的操作;
- Strategy: 策略,定义一个接口,用于所有支持算法的类的公共处理;
- ConcreteStrategy: 具体策略,提供策略的具体实现。
下面是一个示例代码:
package main
import (
"fmt"
)
type PaymentContext struct {
Name, CardNumber, Date string
Amount float32
strategy PaymentStrategy
}
func NewPaymentContext(name, cardNumber, date string, amount float32, strategy PaymentStrategy) *PaymentContext {
return &PaymentContext{
Name: name,
CardNumber: cardNumber,
Date: date,
Amount: amount,
strategy: strategy,
}
}
func (c *PaymentContext) SetStrategy(strategy PaymentStrategy) {
c.strategy = strategy
}
func (c *PaymentContext) Pay() {
fmt.Printf("Customer: %s, CardNumber: %s, Date: %s, Amount: %f\n", c.Name, c.CardNumber, c.Date, c.Amount)
c.strategy.Pay(c.Amount)
}
type PaymentStrategy interface {
Pay(float32)
}
type CreditCardStrategy struct{}
func (s *CreditCardStrategy) Pay(amount float32) {
fmt.Printf("Credit Card payment amount: %f\n", amount)
}
type PayPalStrategy struct{}
func (s *PayPalStrategy) Pay(amount float32) {
fmt.Printf("PayPal payment amount: %f\n", amount)
}
func main() {
creditCardStrategy := &CreditCardStrategy{}
paypalStrategy := &PayPalStrategy{}
context := NewPaymentContext("John", "123456789", "01/01/2022", 100.0, creditCardStrategy)
context.Pay()
context.SetStrategy(paypalStrategy)
context.Pay()
}
在上面的代码中,Context实现了策略模式的关键概念之一,它仅包含策略的引用,并将其传递给实现策略接口的具体函数。具体的策略实现在ConcreteStrategy中。
总结
策略模式是一种简单但非常强大的设计模式。它将算法的选择与使用它的客户代码分离,并使得更改算法变得容易。这种模式可以改进代码的可维护性,并提高代码的复用性。在Go中,使用策略模式需要特别注意接口的使用,以实现不同的策略。