策略模式(Strategy Pattern)详解

什么是策略模式

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

策略模式解决的问题

策略模式主要解决以下问题:

  1. 消除条件语句:避免使用大量的 if-elseswitch-case 语句来选择不同的算法
  2. 算法的动态切换:允许在运行时动态地切换算法
  3. 算法的封装:将算法的实现细节封装起来,对客户端隐藏
  4. 代码复用:通过接口复用不同的算法实现
  5. 遵循开闭原则:可以在不修改现有代码的情况下添加新的算法

策略模式的好处

  1. 灵活性:可以轻松切换不同的算法实现
  2. 可维护性:每个算法都有自己的类,职责单一,易于维护
  3. 可扩展性:可以通过添加新的策略类来扩展功能
  4. 可读性:避免了复杂的条件判断,代码结构清晰
  5. 符合设计原则:遵循开闭原则和单一职责原则

策略模式的结构

策略模式包含以下几个角色:

  1. 策略接口(Strategy):定义所有支持的算法的公共接口
  2. 具体策略(Concrete Strategy):实现策略接口的具体算法
  3. 上下文(Context):持有一个策略对象的引用,使用策略对象执行算法

各语言实现

C++ 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <iostream>
#include <string>

// 策略接口
class PaymentStrategy {
public:
virtual ~PaymentStrategy() = default;
virtual void pay(int amount) = 0;
};

// 具体策略:信用卡支付
class CreditCardPayment : public PaymentStrategy {
private:
std::string cardNumber;
std::string cardHolder;

public:
CreditCardPayment(const std::string& number, const std::string& holder)
: cardNumber(number), cardHolder(holder) {}

void pay(int amount) override {
std::cout << "用信用卡支付 " << amount << " 元,卡号:" << cardNumber << std::endl;
}
};

// 具体策略:支付宝支付
class AlipayPayment : public PaymentStrategy {
private:
std::string account;

public:
AlipayPayment(const std::string& acc) : account(acc) {}

void pay(int amount) override {
std::cout << "用支付宝支付 " << amount << " 元,账号:" << account << std::endl;
}
};

// 上下文:购物车
class ShoppingCart {
private:
PaymentStrategy* paymentStrategy;

public:
void setPaymentStrategy(PaymentStrategy* strategy) {
paymentStrategy = strategy;
}

void checkout(int amount) {
paymentStrategy->pay(amount);
}
};

// 客户端代码
int main() {
ShoppingCart cart;

// 使用信用卡支付
CreditCardPayment creditCard("1234-5678-9012-3456", "张三");
cart.setPaymentStrategy(&creditCard);
cart.checkout(100);

// 切换到支付宝支付
AlipayPayment alipay("zhangsan@example.com");
cart.setPaymentStrategy(&alipay);
cart.checkout(200);

return 0;
}

Java 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// 策略接口
interface PaymentStrategy {
void pay(int amount);
}

// 具体策略:信用卡支付
class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
private String cardHolder;

public CreditCardPayment(String number, String holder) {
this.cardNumber = number;
this.cardHolder = holder;
}

@Override
public void pay(int amount) {
System.out.println("用信用卡支付 " + amount + " 元,卡号:" + cardNumber);
}
}

// 具体策略:支付宝支付
class AlipayPayment implements PaymentStrategy {
private String account;

public AlipayPayment(String account) {
this.account = account;
}

@Override
public void pay(int amount) {
System.out.println("用支付宝支付 " + amount + " 元,账号:" + account);
}
}

// 上下文:购物车
class ShoppingCart {
private PaymentStrategy paymentStrategy;

public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}

public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}

// 客户端代码
public class StrategyPatternDemo {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();

// 使用信用卡支付
CreditCardPayment creditCard = new CreditCardPayment("1234-5678-9012-3456", "张三");
cart.setPaymentStrategy(creditCard);
cart.checkout(100);

// 切换到支付宝支付
AlipayPayment alipay = new AlipayPayment("zhangsan@example.com");
cart.setPaymentStrategy(alipay);
cart.checkout(200);
}
}

Python 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 策略接口
from abc import ABC, abstractmethod

class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount):
pass

# 具体策略:信用卡支付
class CreditCardPayment(PaymentStrategy):
def __init__(self, card_number, card_holder):
self.card_number = card_number
self.card_holder = card_holder

def pay(self, amount):
print(f"用信用卡支付 {amount} 元,卡号:{self.card_number}")

# 具体策略:支付宝支付
class AlipayPayment(PaymentStrategy):
def __init__(self, account):
self.account = account

def pay(self, amount):
print(f"用支付宝支付 {amount} 元,账号:{self.account}")

# 上下文:购物车
class ShoppingCart:
def __init__(self):
self.payment_strategy = None

def set_payment_strategy(self, strategy):
self.payment_strategy = strategy

def checkout(self, amount):
self.payment_strategy.pay(amount)

# 客户端代码
if __name__ == "__main__":
cart = ShoppingCart()

# 使用信用卡支付
credit_card = CreditCardPayment("1234-5678-9012-3456", "张三")
cart.set_payment_strategy(credit_card)
cart.checkout(100)

# 切换到支付宝支付
alipay = AlipayPayment("zhangsan@example.com")
cart.set_payment_strategy(alipay)
cart.checkout(200)

C# 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
using System;

// 策略接口
interface IPaymentStrategy {
void Pay(int amount);
}

// 具体策略:信用卡支付
class CreditCardPayment : IPaymentStrategy {
private string cardNumber;
private string cardHolder;

public CreditCardPayment(string number, string holder) {
this.cardNumber = number;
this.cardHolder = holder;
}

public void Pay(int amount) {
Console.WriteLine($"用信用卡支付 {amount} 元,卡号:{cardNumber}");
}
}

// 具体策略:支付宝支付
class AlipayPayment : IPaymentStrategy {
private string account;

public AlipayPayment(string account) {
this.account = account;
}

public void Pay(int amount) {
Console.WriteLine($"用支付宝支付 {amount} 元,账号:{account}");
}
}

// 上下文:购物车
class ShoppingCart {
private IPaymentStrategy paymentStrategy;

public void SetPaymentStrategy(IPaymentStrategy strategy) {
this.paymentStrategy = strategy;
}

public void Checkout(int amount) {
paymentStrategy.Pay(amount);
}
}

// 客户端代码
class Program {
static void Main(string[] args) {
ShoppingCart cart = new ShoppingCart();

// 使用信用卡支付
CreditCardPayment creditCard = new CreditCardPayment("1234-5678-9012-3456", "张三");
cart.SetPaymentStrategy(creditCard);
cart.Checkout(100);

// 切换到支付宝支付
AlipayPayment alipay = new AlipayPayment("zhangsan@example.com");
cart.SetPaymentStrategy(alipay);
cart.Checkout(200);
}
}

策略模式的适用场景

策略模式适用于以下情况:

  1. 需要多种算法选择:当一个问题有多种解决方案,需要根据不同情况选择不同的算法时
  2. 算法需要动态切换:当需要在运行时动态切换算法时
  3. 避免复杂条件判断:当使用大量的条件语句来选择算法时
  4. 算法需要封装:当需要将算法的实现细节对客户端隐藏时
  5. 需要遵循开闭原则:当需要在不修改现有代码的情况下添加新的算法时

实际应用场景

  1. 支付系统:不同的支付方式(信用卡、支付宝、微信支付等)
  2. 排序算法:不同的排序策略(快速排序、归并排序、冒泡排序等)
  3. 压缩算法:不同的压缩策略(ZIP、RAR、7Z等)
  4. 日志系统:不同的日志输出策略(控制台、文件、数据库等)
  5. 图形绘制:不同的绘制策略(2D、3D等)
  6. 游戏AI:不同的AI行为策略

注意事项

  1. 策略数量:如果策略数量过多,可能会导致类的数量激增
  2. 策略选择:客户端需要知道有哪些策略可供选择
  3. 性能考虑:如果策略的创建成本较高,可以考虑使用享元模式
  4. 状态管理:策略对象通常是无状态的,如果需要维护状态,需要谨慎设计

总结

策略模式是一种非常实用的设计模式,它通过将算法封装成独立的策略类,使算法的选择和使用更加灵活。策略模式不仅可以消除复杂的条件判断,还可以提高代码的可维护性和可扩展性。在实际开发中,当遇到多种算法选择的场景时,策略模式是一个很好的解决方案。