C++设计模式之行为型模式:策略模式(Strategy)

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

一、核心思想与角色

策略模式的核心是"算法封装与动态切换",通过将不同算法分离为独立的策略类,使客户端可以根据需求选择或切换算法。其核心角色如下:

角色名称 核心职责
抽象策略(Strategy) 定义所有支持的算法的公共接口,声明算法的执行方法。
具体策略(ConcreteStrategy) 实现抽象策略接口,包含具体的算法逻辑。
环境类(Context) 持有一个策略对象的引用,提供设置策略的接口,在需要时调用策略的执行方法。

核心思想:将算法的定义与使用分离,客户端通过环境类间接使用策略,可在运行时动态更换策略,而无需修改使用算法的代码。

二、实现示例(支付方式选择)

假设我们需要设计一个电商支付系统,支持多种支付方式(如支付宝、微信支付、银联支付),用户可根据需求选择不同支付方式。使用策略模式可将每种支付方式封装为独立策略,实现灵活切换:

cpp 复制代码
#include <iostream>
#include <string>

// 1. 抽象策略:支付方式
class PaymentStrategy {
public:
    // 纯虚方法:执行支付
    virtual void pay(double amount) = 0;
    virtual ~PaymentStrategy() = default;
};

// 2. 具体策略1:支付宝支付
class AlipayStrategy : public PaymentStrategy {
private:
    std::string account; // 支付宝账号

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

    void pay(double amount) override {
        std::cout << "使用支付宝账号[" << account << "]支付了 " << amount << " 元" << std::endl;
        // 实际支付逻辑:调用支付宝API...
    }
};

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

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

    void pay(double amount) override {
        std::cout << "使用微信OpenID[" << openId << "]支付了 " << amount << " 元" << std::endl;
        // 实际支付逻辑:调用微信支付API...
    }
};

// 2. 具体策略3:银联支付
class UnionPayStrategy : public PaymentStrategy {
private:
    std::string cardNumber; // 银行卡号

public:
    UnionPayStrategy(const std::string& card) : cardNumber(card) {}

    void pay(double amount) override {
        std::cout << "使用银联卡[" << cardNumber << "]支付了 " << amount << " 元" << std::endl;
        // 实际支付逻辑:调用银联API...
    }
};

// 3. 环境类:订单支付上下文
class PaymentContext {
private:
    PaymentStrategy* strategy; // 当前支付策略

public:
    // 构造时指定初始策略
    PaymentContext(PaymentStrategy* strat) : strategy(strat) {}

    // 动态更换支付策略
    void setStrategy(PaymentStrategy* newStrat) {
        strategy = newStrat;
    }

    // 执行支付(委托给当前策略)
    void pay(double amount) {
        if (strategy) {
            strategy->pay(amount);
        } else {
            std::cout << "未设置支付方式,支付失败" << std::endl;
        }
    }
};

// 客户端代码:使用支付系统
int main() {
    // 创建具体支付策略
    PaymentStrategy* alipay = new AlipayStrategy("user123@alipay.com");
    PaymentStrategy* wechat = new WechatPayStrategy("o6_bmjrPTlm6_2sgVt7hMZOPfL2M");
    PaymentStrategy* unionpay = new UnionPayStrategy("6222 **** **** 1234");

    // 创建支付上下文(环境类),初始使用支付宝
    PaymentContext* payment = new PaymentContext(alipay);

    // 支付订单1
    std::cout << "=== 订单1支付 ===" << std::endl;
    payment->pay(99.9);

    // 切换为微信支付,支付订单2
    std::cout << "\n=== 订单2支付 ===" << std::endl;
    payment->setStrategy(wechat);
    payment->pay(199.5);

    // 切换为银联支付,支付订单3
    std::cout << "\n=== 订单3支付 ===" << std::endl;
    payment->setStrategy(unionpay);
    payment->pay(599.0);

    // 释放资源
    delete unionpay;
    delete wechat;
    delete alipay;
    delete payment;

    return 0;
}

三、代码解析

  1. 抽象策略(PaymentStrategy)

    定义了pay()纯虚方法,声明所有支付方式必须实现的支付接口,参数为支付金额。

  2. 具体策略

    每种支付方式对应一个具体策略类,实现pay()方法封装各自的支付逻辑:

    • AlipayStrategy:支付宝支付,需要支付宝账号。
    • WechatPayStrategy:微信支付,需要微信OpenID。
    • UnionPayStrategy:银联支付,需要银行卡号。
      每个策略类专注于自身的支付实现,与其他策略相互独立。
  3. 环境类(PaymentContext)

    • 持有当前支付策略的引用(strategy),通过setStrategy()方法支持动态切换策略。
    • 提供pay()方法,将支付操作委托给当前策略的pay()方法,客户端无需直接调用策略。
  4. 客户端使用

    客户端创建具体策略和环境类,通过环境类执行支付;需要更换支付方式时,调用setStrategy()切换策略,无需修改支付逻辑代码。

四、核心优势与适用场景

优势
  1. 算法解耦:将算法与使用算法的客户端分离,算法的修改或新增不影响客户端。
  2. 动态切换:支持在运行时动态更换算法(如示例中切换支付方式),灵活性高。
  3. 代码复用:不同环境可共享同一策略对象,避免代码重复。
  4. 符合开闭原则:新增算法只需添加新的策略类,无需修改现有代码。
  5. 替代条件判断 :用策略选择替代if-elseswitch-case,使代码更清晰。
适用场景
  1. 多种算法可选:如排序算法(快速排序、冒泡排序)、支付方式、折扣计算方式。
  2. 算法需要动态切换:如根据用户设置切换压缩算法、根据网络状况切换传输协议。
  3. 避免算法与客户端耦合:如框架设计中允许用户自定义插件(策略)。
  4. 算法逻辑复杂:当算法包含多个步骤或变体时,封装为策略可提高可读性。

五、与其他模式的区别

模式 核心差异点
策略模式 封装可互换的算法,客户端可动态选择,强调"算法替换"。
状态模式 封装对象的状态,状态决定行为且可自动转换,强调"状态驱动行为"。
模板方法 定义算法骨架,子类实现具体步骤,强调"固定流程+可变步骤"。
工厂模式 用于创建对象,可与策略模式结合(工厂创建策略对象),但不涉及算法执行。

六、实践建议

  1. 策略工厂结合 :使用工厂模式创建策略对象,减少客户端对具体策略的依赖(如PaymentStrategyFactory根据类型创建支付策略)。
  2. 策略缓存复用:对于无状态的策略(如无成员变量的算法),可缓存策略对象避免重复创建(类似单例)。
  3. 策略参数化 :通过构造函数或setter方法为策略传递参数(如示例中的账号信息),提高灵活性。
  4. 避免策略膨胀:当策略过多时,可结合享元模式共享策略对象,或使用组合模式拆分复杂策略。

策略模式的核心价值在于"算法的模块化与动态化",它通过将算法封装为独立策略,使系统能灵活适应算法的变化,同时保持客户端代码的稳定。在需要提供多种可选方案或算法可能频繁变更的场景中,策略模式是实现代码灵活性和可维护性的理想选择。

相关推荐
泽虞3 小时前
《Qt应用开发》笔记p4
linux·开发语言·数据库·c++·笔记·qt·算法
ajassi20003 小时前
开源 C++ QT QML 开发(十三)多线程
c++·qt·开源
mahuifa3 小时前
C++(Qt)软件调试---binutils工具集详解(39)
linux·c++·软件调试·binutils
Qt程序员3 小时前
Qt C++ 教程:无边框窗体 + 自定义标题栏 + 圆角 + 拖拽拉升 + 阴影
c++·qt·qt编程·qt开发·qt教程·qt界面开发·qt界面
泽虞3 小时前
《Qt应用开发》笔记p5
linux·开发语言·c++·笔记·qt·算法
qq_433554543 小时前
C++ 完全背包时间优化、完全背包空间优化
开发语言·c++·动态规划
另寻沧海10 小时前
测试中的 AAA 模式与 Given–When–Then 模式详解
c++·单元测试·测试覆盖率
Q741_14711 小时前
C++ 模拟题 力扣495. 提莫攻击 题解 每日一题
c++·算法·leetcode·模拟
阿维的博客日记13 小时前
设计模式-代理模式
设计模式·代理模式