C++ 策略模式实战:从原理到落地

策略模式是 C++ 中经典的行为型设计模式 ,核心思想是「将算法封装成独立策略类,让算法可动态替换」,既能避免大量if-else分支,又能提高代码扩展性。下面从「原理拆解 + 实战案例」两部分,带你彻底掌握策略模式的落地用法。


一、策略模式核心原理

1. 核心角色(3 个)

  • 抽象策略类(Strategy):定义算法的统一接口(纯虚函数),所有具体策略需实现该接口。
  • 具体策略类(ConcreteStrategy):实现抽象策略接口,封装不同的算法逻辑。
  • 上下文类(Context):持有策略对象的引用,对外提供统一调用入口,可动态切换策略。

2. 核心优势

  • 消除分支判断:替代if-else/switch,代码更简洁。
  • 开闭原则:新增算法只需加新策略类,无需修改原有代码。
  • 算法复用:策略类可在不同场景复用。

二、实战案例:电商订单折扣计算

场景说明

电商订单需根据用户类型(普通用户、VIP、超级 VIP)计算不同折扣,若用if-else会导致代码臃肿,用策略模式可优雅解决。

完整实战代码

cpp

运行

复制代码
#include <iostream>
#include <string>
#include <memory> // 智能指针,避免内存泄漏

// 1. 抽象策略类:折扣计算接口
class DiscountStrategy {
public:
    // 纯虚函数:计算折扣后价格
    virtual double calculate(double originalPrice) = 0;
    // 虚析构:确保子类析构被调用
    virtual ~DiscountStrategy() = default;
};

// 2. 具体策略类1:普通用户(无折扣)
class NormalUserDiscount : public DiscountStrategy {
public:
    double calculate(double originalPrice) override {
        std::cout << "普通用户:无折扣\n";
        return originalPrice;
    }
};

// 具体策略类2:VIP用户(9折)
class VipUserDiscount : public DiscountStrategy {
public:
    double calculate(double originalPrice) override {
        std::cout << "VIP用户:9折优惠\n";
        return originalPrice * 0.9;
    }
};

// 具体策略类3:超级VIP用户(8折+满100减10)
class SuperVipUserDiscount : public DiscountStrategy {
public:
    double calculate(double originalPrice) override {
        std::cout << "超级VIP用户:8折+满100减10\n";
        double price = originalPrice * 0.8;
        // 满100减10
        if (price >= 100) {
            price -= 10;
        }
        return price;
    }
};

// 3. 上下文类:订单(封装策略调用)
class Order {
private:
    // 持有策略对象(智能指针自动管理内存)
    std::unique_ptr<DiscountStrategy> discount_strategy_;
    double original_price_; // 原价
public:
    // 构造函数:初始化原价+策略
    Order(double price, std::unique_ptr<DiscountStrategy> strategy)
        : original_price_(price), discount_strategy_(std::move(strategy)) {}

    // 动态切换策略(核心:运行时替换算法)
    void setDiscountStrategy(std::unique_ptr<DiscountStrategy> strategy) {
        discount_strategy_ = std::move(strategy);
    }

    // 对外统一接口:计算最终价格
    double getFinalPrice() {
        if (!discount_strategy_) {
            throw std::runtime_error("未设置折扣策略!");
        }
        return discount_strategy_->calculate(original_price_);
    }
};

// 测试代码
int main() {
    // 订单原价200元
    double original_price = 200.0;

    // 1. 普通用户订单
    Order normal_order(original_price, std::make_unique<NormalUserDiscount>());
    std::cout << "普通用户最终价格:" << normal_order.getFinalPrice() << "元\n";

    // 2. 切换为VIP策略
    normal_order.setDiscountStrategy(std::make_unique<VipUserDiscount>());
    std::cout << "VIP用户最终价格:" << normal_order.getFinalPrice() << "元\n";

    // 3. 切换为超级VIP策略
    normal_order.setDiscountStrategy(std::make_unique<SuperVipUserDiscount>());
    std::cout << "超级VIP最终价格:" << normal_order.getFinalPrice() << "元\n";

    return 0;
}

代码运行结果

plaintext

复制代码
普通用户:无折扣
普通用户最终价格:200元
VIP用户:9折优惠
VIP用户最终价格:180元
超级VIP用户:8折+满100减10
超级VIP最终价格:150元

代码关键解析

  1. 抽象策略类DiscountStrategy :定义了calculate纯虚函数,是所有折扣算法的统一接口。
  2. 具体策略类 :NormalUserDiscount/VipUserDiscount/SuperVipUserDiscount分别实现不同折扣逻辑,彼此独立。
  3. 上下文类Order :
    • 持有策略对象指针,对外隐藏具体算法细节;
    • 提供setDiscountStrategy方法,支持运行时动态切换策略;
    • getFinalPrice是统一调用入口,用户无需关心具体折扣逻辑。
  4. 智能指针 :使用std::unique_ptr管理策略对象,避免手动释放内存,符合 C++ 现代编程规范。

三、策略模式实战扩展技巧

  1. 策略工厂:若策略类型多,可封装「策略工厂类」,根据用户类型自动创建对应策略对象,进一步简化调用。
  2. 结合 lambda:简单策略可直接用 lambda 表达式替代策略类,减少代码量(适合轻量级场景)。
  3. 策略配置化:将策略与配置文件绑定(如 JSON),无需改代码即可调整算法逻辑。

总结

  1. 策略模式核心是「算法与使用场景解耦」,通过抽象策略接口 + 具体策略类,实现算法的动态替换。
  2. 实战中需明确「抽象策略接口」「具体策略实现」「上下文封装」三个核心角色,避免过度设计。
  3. C++ 中推荐用智能指针管理策略对象,结合开闭原则,新增算法只需扩展策略类,无需修改原有代码。
相关推荐
熊猫钓鱼>_>7 分钟前
鸿蒙PC高分屏与键鼠交互适配:DPI缩放、右键菜单一次讲清
开发语言·笔记·华为·ai编程·harmonyos·鸿蒙·鸿蒙心迹
octopus_c40 分钟前
C++ 运算符重载详解 && 日期类的实现
开发语言·c++
青少儿编程课堂43 分钟前
2026蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:堆排序与优先队列解析
c++·python·算法·bfs·信息学竞赛
Eiceblue44 分钟前
用 Python 给 Word 文档加水印:文字、图片与批量处理
开发语言·vscode·python·word
j7~1 小时前
【C++ 面试笔记】(篇二):类与数据抽象 & STL 容器与算法
开发语言·c++·面试·stl容器和算法·类和数据抽象
Fuyo_11191 小时前
深入解析 C++ unordered_set 与 unordered_map 的核心特性与性能实战
开发语言·c++
码匠许师傅1 小时前
【C++三方组件】FFmpeg:音视频处理的瑞士军刀
c++·ffmpeg·音视频
ShineWinsu2 小时前
对于Qt:QPushButton常见属性的解析
开发语言·c++·qt·api·gui·按钮·qpushbutton
外贸GEO优化2 小时前
外贸独立站的可抓取性:JS 渲染、懒加载与无限滚动到底影响什么
开发语言·javascript·ecmascript
飞浪纪元[FWC–FE]2 小时前
Qt 工程创建与 CMake / qmake 构建规范
开发语言·数据库·qt