当前位置: 首页 > news >正文

深入浅出策略模式:一个C++模板实现的灵活策略管理库

个人专著《C++元编程与通用设计模式实现》由清华大学出版社出版。该书内容源于工业级项目实践,出版后市场反馈积极(已加印)。其专业价值获得了图书馆系统的广泛认可:不仅被中国国家图书馆作为流通与保存本收藏,还被近半数省级公共图书馆及清华大学、浙江大学等超过35所高校图书馆收录为馆藏。

个人软仓,gitee搜索“galaxy_0”

深入浅出策略模式:一个C++模板实现的灵活策略管理库

1. 策略模式简介

在软件开发中,我们常常会遇到这样的情况:根据不同的条件,需要采用不同的处理方式。比如支付时根据用户选择的渠道调用不同的接口,或者游戏角色根据状态触发不同的技能。传统的if-else或switch虽然简单直接,但随着条件增多,代码会变得臃肿且难以维护。这时候,策略模式就派上用场了——它把每个算法封装成独立的策略,让它们可以互相替换,就像更换工具一样方便。

今天,我将带你认识一个基于C++模板实现的策略模式管理库。它利用std::functionstd::unordered_map,将策略与键绑定,支持普通函数、lambda、成员函数等多种可调用对象,而且接口非常简洁。无论你是C++新手还是老手,都能轻松上手。

2. 代码设计解析

2.1 整体设计思路

这个库的核心思想其实很简单:用一把“钥匙”(键)对应一个“策略”(函数)。我们需要什么策略,就用对应的钥匙去取。为了做到这一点,它借助了C++标准库中的std::unordered_map来存储键值对,而值的类型是std::function<Ret(Args...)>——一个能够包装任何可调用对象的万能容器。

但问题来了:用户可能用普通函数指针、lambda、成员函数等各种方式定义策略,它们的类型各不相同。怎么让它们都能被std::function接纳呢?答案就是模板特化。库通过三个特化版本,自动将各种函数类型转换为统一的std::function,从而实现了“一次编写,随处可用”的便利。

2.2 类模板结构

先看主模板,它只是一个空架子,真正的实现在特化版本中:

template<typenamekeyType,typenamefuncType>structstrategy{};

第一个特化:针对std::function类型
这是最核心的版本,内部维护了一个unordered_map,键是keyType,值是std::function<Ret(Args...)>

template<typenamekeyType,typenameRet,typename...Args>classstrategy<keyType,std::function<Ret(Args...)>>{public:usingcallee_type=std::function<Ret(Args...)>;usingiterator=typenamestd::unordered_map<keyType,callee_type>::iterator;protected:std::unordered_map<keyType,callee_type>m_strates__;// 策略仓库public:strategy(){}virtual~strategy(){}// 添加策略template<typenameFunct_t>booladd(constkeyType&key,Funct_t&&callFn);// 移除策略boolerase(constkeyType&key);// 清空策略voidclear();// 获取策略数量size_tcount();// 对所有策略执行一次(不关心返回值)template<typename...Params>voidcall_each(Params&&...args);// 根据键执行策略,返回结果template<typename...Params>Retcall(constkeyType&key,Params&&...args);};

add方法在键不存在时插入新的策略,erase移除指定键,clear一键清空,count告诉你仓库里有多少策略。
call_each会遍历所有策略并依次调用,适合广播场景;call则根据键找到对应的策略并执行,如果找不到,会抛出std::runtime_error异常。

第二个特化:支持普通函数指针
为了让用户能直接用函数类型(如void(int))实例化,库提供了这个继承版本:

template<typenamekeyType,typenameRet,typename...Args>classstrategy<keyType,Ret(Args...)>:publicstrategy<keyType,std::function<Ret(Args...)>>{};

这样,strategy<int, void(int)>就等价于strategy<int, std::function<void(int)>>,省去了手动包装的麻烦。

第三个特化:支持成员函数指针
如果你想把某个类的成员函数作为策略,这个特化会帮你自动转换成对应的std::function

template<typenamekeyType,typenameclassType,typenamefuncType>classstrategy<keyType,funcType classType::*>:publicstrategy<keyType,std::function<funcType>>{};

比如strategy<int, decltype(&MyClass::method)>也能正常工作。

2.3 关键方法实现

  • add:使用了完美转发,将传入的可调用对象直接构造为std::function,然后插入map。如果键已存在,则添加失败(返回false),避免意外覆盖。
  • call:先在map中查找键,找到就直接调用函数,并将参数完美转发进去;找不到则抛出异常。
  • call_each:简单遍历map,依次调用每个函数,忽略返回值。

所有方法都通过模板支持任意参数列表,非常灵活。

3. 使用示例

3.1 统一接口策略(继承同一接口)

假设我们有一组策略类,都继承自同一个基类stra_base,实现了统一的callee接口:

classstra_base{public:virtualvoidcallee(inta)=0;virtual~stra_base(){}
http://www.cnnetsun.cn/news/1262059.html

相关文章:

  • SFT构造数据的一些经验
  • 打卡信奥刷题(2945)用C++实现信奥题 P5864 [SEERC 2018] Broken Watch
  • 丝杆升降机如何正确选型?参数、工况、电机匹配一篇讲透
  • MATLAB R2021B环境下基于Takagi-Sugeno-Kang模糊神经网络的时间序列...
  • LeetCode102.二叉树层序遍历
  • 霸王餐券预扣库存场景下,如何防止同一用户多设备并发“薅羊毛”
  • 力扣解题-200. 岛屿数量
  • 国内代理 IP 的类型:住宅 IP、机房 IP、移动 4G/5G IP 区别
  • AI 内容导出乱、格式崩、公式变?我开发了这只鸭子帮我全解决了
  • 智能楼道灯控制器(有完整资料)
  • AI安全应用实战复盘:一场2小时的深度交流,我们聊了什么?
  • esp网络时钟
  • 【无线通信】基于matlab统计信道的低复杂度旋转和位置优化为6D可移动天线无线通信【含Matlab源码 15160期】
  • 2026年,一周就能背完的web前端八股文!(春招最新附答案)!
  • 根据文章举报数量确定推荐
  • NineData 社区版 V4.10.0 发布:新增 9 条异构数据库复制链路,DevOps 能力再升级!
  • Redis知识点
  • 简单 的部分背包问题(贪心算法)
  • Kmeans聚类与肘部法确定聚类个数:Matlab实战
  • COMSOL 激光烧蚀3D体热源引力场温度场仿真探索
  • 使用Springboot实现MQTT通信
  • 多智能体事件触发一致性
  • 类内部方法内 写创建对象
  • GraphRAG 完全指南
  • 非计算机专业如何顺利转行网络安全领域?_如何转行网络安全工程师
  • 基于自适应PI的构网型变流器预同步控制策略复现报告
  • 【跨模态一致性增强模块+开源代码】定位与验证:一个提升深度伪造检测的双流网络
  • 如何从bode图得到单位阶跃的趋势
  • 大数据领域 ETL 中的元数据管理策略
  • 企业微信外部客户群自动化管理:建群+群发+踢人一体化