策略模式(Strategy Pattern)详解
什么是策略模式
策略模式是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户端。
策略模式解决的问题
策略模式主要解决以下问题:
- 消除条件语句:避免使用大量的
if-else 或 switch-case 语句来选择不同的算法
- 算法的动态切换:允许在运行时动态地切换算法
- 算法的封装:将算法的实现细节封装起来,对客户端隐藏
- 代码复用:通过接口复用不同的算法实现
- 遵循开闭原则:可以在不修改现有代码的情况下添加新的算法
策略模式的好处
- 灵活性:可以轻松切换不同的算法实现
- 可维护性:每个算法都有自己的类,职责单一,易于维护
- 可扩展性:可以通过添加新的策略类来扩展功能
- 可读性:避免了复杂的条件判断,代码结构清晰
- 符合设计原则:遵循开闭原则和单一职责原则
策略模式的结构
策略模式包含以下几个角色:
- 策略接口(Strategy):定义所有支持的算法的公共接口
- 具体策略(Concrete Strategy):实现策略接口的具体算法
- 上下文(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); } }
|
策略模式的适用场景
策略模式适用于以下情况:
- 需要多种算法选择:当一个问题有多种解决方案,需要根据不同情况选择不同的算法时
- 算法需要动态切换:当需要在运行时动态切换算法时
- 避免复杂条件判断:当使用大量的条件语句来选择算法时
- 算法需要封装:当需要将算法的实现细节对客户端隐藏时
- 需要遵循开闭原则:当需要在不修改现有代码的情况下添加新的算法时
实际应用场景
- 支付系统:不同的支付方式(信用卡、支付宝、微信支付等)
- 排序算法:不同的排序策略(快速排序、归并排序、冒泡排序等)
- 压缩算法:不同的压缩策略(ZIP、RAR、7Z等)
- 日志系统:不同的日志输出策略(控制台、文件、数据库等)
- 图形绘制:不同的绘制策略(2D、3D等)
- 游戏AI:不同的AI行为策略
注意事项
- 策略数量:如果策略数量过多,可能会导致类的数量激增
- 策略选择:客户端需要知道有哪些策略可供选择
- 性能考虑:如果策略的创建成本较高,可以考虑使用享元模式
- 状态管理:策略对象通常是无状态的,如果需要维护状态,需要谨慎设计
总结
策略模式是一种非常实用的设计模式,它通过将算法封装成独立的策略类,使算法的选择和使用更加灵活。策略模式不仅可以消除复杂的条件判断,还可以提高代码的可维护性和可扩展性。在实际开发中,当遇到多种算法选择的场景时,策略模式是一个很好的解决方案。