策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。这种模式让算法的变化独立于使用算法的客户端,从而提高代码的灵活性和可维护性。

策略模式的核心角色

  1. 抽象策略(Strategy):定义所有支持的算法的公共接口
  2. 具体策略(Concrete Strategy):实现抽象策略接口,提供具体的算法实现
  3. 上下文(Context):持有一个策略对象的引用,负责使用策略对象,隔离客户端与策略的直接交互

策略模式的实现示例

下面以"支付系统"为例展示策略模式的实现,系统支持多种支付方式(如支付宝、微信支付、信用卡支付),这些支付方式可以相互替换:

#include <iostream>
#include <string>
#include <memory>

// 抽象策略:支付方式
class PaymentStrategy {
public:
    virtual void pay(double amount) const = 0;
    virtual ~PaymentStrategy() = default;
};

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

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

    void pay(double amount) const override {
        std::cout << "使用支付宝账户 " << account 
                  << " 支付了 " << amount << " 元" << std::endl;
    }
};

// 具体策略:微信支付
class WechatPayStrategy : public PaymentStrategy {
private:
    std::string openId;

public:
    WechatPayStrategy(const std::string& id) : openId(id) {}

    void pay(double amount) const override {
        std::cout << "使用微信账号 " << openId 
                  << " 支付了 " << amount << " 元" << std::endl;
    }
};

// 具体策略:信用卡支付
class CreditCardStrategy : public PaymentStrategy {
private:
    std::string cardNumber;
    std::string name;
    std::string cvv;
    std::string expiryDate;

public:
    CreditCardStrategy(const std::string& num, const std::string& n, 
                     const std::string& c, const std::string& exp)
        : cardNumber(num), name(n), cvv(c), expiryDate(exp) {}

    void pay(double amount) const override {
        std::cout << "使用信用卡 " << cardNumber << " (" << name 
                  << ") 支付了 " << amount << " 元" << std::endl;
    }
};

// 上下文:购物车
class ShoppingCart {
private:
    std::unique_ptr<PaymentStrategy> paymentStrategy;

public:
    // 设置支付策略
    void setPaymentStrategy(std::unique_ptr<PaymentStrategy> strategy) {
        paymentStrategy = std::move(strategy);
    }

    // 结算
    void checkout(double amount) const {
        if (paymentStrategy) {
            paymentStrategy->pay(amount);
        } else {
            std::cout << "请选择支付方式" << std::endl;
        }
    }
};

// 客户端使用
int main() {
    ShoppingCart cart;
    double totalAmount = 299.99;

    // 使用支付宝支付
    std::cout << "=== 选择支付宝支付 ===" << std::endl;
    cart.setPaymentStrategy(std::make_unique<AlipayStrategy>("user123@alipay.com"));
    cart.checkout(totalAmount);

    // 切换为微信支付
    std::cout << "\n=== 选择微信支付 ===" << std::endl;
    cart.setPaymentStrategy(std::make_unique<WechatPayStrategy>("wx123456789"));
    cart.checkout(totalAmount);

    // 切换为信用卡支付
    std::cout << "\n=== 选择信用卡支付 ===" << std::endl;
    cart.setPaymentStrategy(std::make_unique<CreditCardStrategy>(
        "6222-1234-5678-9012", "张三", "123", "12/25"));
    cart.checkout(totalAmount);

    return 0;
}

策略模式的工作原理

  1. 抽象策略定义了所有算法的通用接口,确保所有具体策略具有一致的方法
  2. 每个具体策略实现了抽象策略的接口,提供不同的算法实现
  3. 上下文类持有一个策略对象,通过调用策略对象的方法来完成具体操作
  4. 客户端可以动态地为上下文设置不同的策略对象,从而改变上下文的行为

策略模式与状态模式的区别

  • 策略模式:算法是相互独立的,客户端显式选择并切换策略
  • 状态模式:状态的切换通常由状态本身或上下文根据条件自动触发,客户端无需知晓

策略模式的应用场景

  1. 当一个系统需要多种算法,且这些算法需要经常切换时
  2. 当一个类定义了多种行为,且这些行为在代码中以多个条件语句的形式出现时(可以用策略模式替代条件语句)
  3. 当需要隐藏算法的实现细节,只暴露其接口时
  4. 当希望客户端可以选择不同算法,而无需了解算法具体实现时

策略模式的优缺点

优点

  • 实现了算法的封装和复用,使算法可以独立于客户端变化
  • 避免了使用多重条件语句,提高了代码的可读性和可维护性
  • 符合开放-封闭原则,新增策略只需添加新的具体策略类,无需修改原有代码
  • 客户端可以动态切换算法,提高了系统的灵活性

缺点

  • 客户端必须了解所有策略,才能选择合适的策略
  • 策略类数量可能过多,增加了系统的复杂度
  • 策略之间不能直接通信,如需共享数据需要引入额外机制

策略模式在C++标准库中也有应用,例如std::sort函数可以接受自定义的比较器(策略),从而改变排序行为;STL中的各种容器适配器也体现了策略模式的思想。在实际开发中,策略模式是处理多变算法的有效工具。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐