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

精读C++20设计模式——行为型设计模式:策略模式

精读C++20设计模式——行为型设计模式:策略模式

前言

​ 我们天天都在用策略模式!标准库的算法在设计上就是一种策略模式!

​ 策略模式的核心想法很简单:把算法/行为从使用它的类中抽离出来,封装成可互换的“策略(Strategy)”,并允许在运行时或编译期替换这些策略,从而实现算法的可扩展、可测试与解耦。


什么是策略模式?

​ 策略模式把一组可以互换的算法封装到独立对象(或类型)中,客户类(Context)通过统一接口使用它们。注意!策略是“可替换的” —— Context 不知道具体实现细节,只依赖策略接口。


动态策略

​ 动态策略通常用虚函数(interface + subclass)或类型擦除(std::function / std::unique_ptr 指向多态对象)实现,优点是运行时可替换,灵活适配配置或用户选择;代价是虚调/间接调用开销和更复杂的生命周期管理。

#include <iostream>
#include <memory>
#include <string>// 策略接口
struct ICompressor {virtual ~ICompressor() = default;virtual std::string compress(const std::string& data) = 0;
};// 具体策略 A
struct GzipCompressor : ICompressor {std::string compress(const std::string& data) override {return "gzip(" + data + ")";}
};// 具体策略 B
struct NoopCompressor : ICompressor {std::string compress(const std::string& data) override {return data;}
};// Context
class CompressionContext {
public:CompressionContext(std::unique_ptr<ICompressor> s) : strategy_(std::move(s)) {}void set_strategy(std::unique_ptr<ICompressor> s) { strategy_ = std::move(s); }std::string perform(const std::string& data) {return strategy_->compress(data);}
private:std::unique_ptr<ICompressor> strategy_;
};int main() {CompressionContext ctx(std::make_unique<NoopCompressor>());std::cout << ctx.perform("hello") << "\n";            // helloctx.set_strategy(std::make_unique<GzipCompressor>());std::cout << ctx.perform("hello") << "\n";            // gzip(hello)
}

​ 如您所见,我们实际上包装了两个压缩策略:这是在外面运行的时候配置的——配置、插件或用户交互决定这一切。策略实现复杂且需要继承/多态;需要在程序运行期间动态替换策略。

注意事项

  • 如果策略是有状态的(内部有成员),要明确其共享/独占语义(shared_ptr vs unique_ptr)。
  • 线程安全:多个线程共享策略实例需要保证策略实现是线程安全或每线程独立实例。
  • 单元测试方便:可以替换为 mock 策略。

静态策略

静态策略利用模板参数或 CRTP 把策略在编译期绑定进 Context。它能带来零虚调用、内联优化和更好性能,但牺牲了运行时切换和二进制大小/可重用性的灵活性。

#include <iostream>
#include <string>// 策略:UpperCaseFormatter / LowerCaseFormatter
struct UpperCaseFormatter {static std::string format(std::string s) {for (auto &c : s) c = static_cast<char>(std::toupper(c));return s;}
};struct LowerCaseFormatter {static std::string format(std::string s) {for (auto &c : s) c = static_cast<char>(std::tolower(c));return s;}
};// Context 模板化
template<typename FormatterPolicy>
class TextProcessor {
public:std::string process(const std::string& s) {return FormatterPolicy::format(s);}
};int main() {TextProcessor<UpperCaseFormatter> up;TextProcessor<LowerCaseFormatter> low;std::cout << up.process("Hello") << "\n"; // HELLOstd::cout << low.process("Hello") << "\n"; // hello
}

​ 当然,有时候既想要运行时灵活性又想要简洁接口,可以考虑使用 std::function 或自定义类型擦除(small-buffer optimization),例如:

#include <functional>
#include <iostream>
#include <string>class Printer {
public:using Strategy = std::function<void(const std::string&)>;Printer(Strategy s) : strategy_(std::move(s)) {}void set_strategy(Strategy s) { strategy_ = std::move(s); }void print(const std::string& s) { strategy_(s); }
private:Strategy strategy_;
};int main() {Printer p([](const std::string& s){ std::cout << "A: " << s << "\n"; });p.print("x");p.set_strategy([](const std::string& s){ std::cout << "B: " << s << "\n"; });p.print("y");
}

std::function 的优点是写法短、易用,但它也有类型擦除和内存/调用开销。适合策略实现比较小或不在超高频路径的情况。


总结

动态策略(运行时)

  • 优点:高度灵活、运行时可替换、适合插件/配置驱动。
  • 缺点:虚调用 / 间接调用开销、需要处理生命周期/并发。

静态策略(编译期)

  • 优点:零虚开销、编译器优化、内联、类型安全。
  • 缺点:缺乏运行时切换、编译单元膨胀(可能增加二进制),策略必须在编译期已知。

类型擦除(std::function / 自定义)

  • 优点:编码方便、接口统一、比虚继承更轻量(在小策略场景)。
  • 缺点:隐藏类型信息、可能有分配/性能开销。
http://www.dtcms.com/a/426690.html

相关文章:

  • Spark专题-第三部分:性能监控与实战优化(1)-认识spark ui
  • 汕头网站设计哪家好鞍山制作网站哪家好
  • 电子商务网站建设试卷软件设计师好考吗
  • 【计算机视觉】形态学的去噪
  • 精读C++20设计模式——行为型设计模式:命令模式
  • petalinux 安装Openblass库
  • 织梦播放器网站网站建设简历自我评价
  • 大数据毕业设计选题推荐-基于大数据的全球经济指标数据分析与可视化系统-Hadoop-Spark-数据可视化-BigData
  • Spring Boot 整合 Redisson 实现分布式锁:实战指南
  • 国鑫发布新一代「海擎」服务器 全面兼容国内外主流OAM GPU
  • 百度电商MultiAgent视频生成系统
  • FRP v0.65.0 内网穿透专业指南(SSH + HTTP/HTTPS 一体化配置)
  • UNIX下C语言编程与实践20-UNIX 文件类型判断:stat 结构 st_mode 与文件类型宏的使用实战
  • 电脑网站开发手机上可以打开吗网站建设如何把代码
  • ROS2下利用遥控手柄控制瑞尔曼RM65-B机器人
  • SOC(安全运营中心)
  • 济南网站建设山东聚搜网推荐传媒公司招聘
  • C++ STL 深度解析:容器、迭代器与算法的协同作战
  • SPI主控的CS引发的读不到设备寄存器
  • 数据标注、Label Studio
  • 央链知播受权发布:图说《“可信资产 IPO + 数链金融 RWA” 链改 2.0 六方共识》
  • 【Proteus8.17仿真】 STM32仿真 0.96OLED 屏幕显示ds1302实时时间
  • 佛山做营销型网站建设wordpress修改域名后无法登陆
  • mysql数据库学习之常用函数(五)
  • 避坑实战!京东商品详情接口开发指南:分页优化、多规格解析与数据完整性保障
  • win10(十二)Nuitka打包程序
  • 【Rust GUI开发入门】编写一个本地音乐播放器(11. 支持动态明暗主题切换)
  • 自己做网站帮公司出认证证书违法吗上海定制网站建设公司
  • [论文阅读] AI + 软件工程(Debug)| 告别 “猜 bug”:TreeMind 用 LLM+MCTS 破解 Android 不完整报告复现难题
  • ESP32 + MCP over MQTT:通过大模型控制智能硬件设备