【设计模式】策略模式:可插拔算法,从硬编码到灵活适配,体会“算法解耦“思想

【设计模式】策略模式:可插拔算法,从硬编码到灵活适配,体会“算法解耦“思想

请添加图片描述

半桔个人主页
 🔥 个人专栏: 《设计模式》《手撕面试算法》《C++从入门到入土》

🔖恐惧囚禁人的灵魂,希望可以让你自由。《肖申克的救赎》

文章目录

一. 光头强转行

1.1 团结屯的故事

我是光头强。以前,我每天的生活就是被两头臭狗熊按在地上摩擦,不仅树砍不到,还要承受李老板的夺命连环Call和扣工资威胁。

直到有一天,我捡到了一本《C++ Primer》(虽然我也忘了森林里为啥会有这书)。那一刻,我悟了!砍树是没有前途的,计算机才是第一生产力

我狠下心来闭关修炼,左手C++,右手面向对象(OO),发际线虽然更高了(额,我好像也没什么头发),但我感觉自己强得可怕。于是,我把电锯一扔,拿起键盘,给李老板发了辞职信:“世界那么大,我想去敲代码。”

李老板一听我要走,顿时慌了:“强子!你走了,《熊出没》还怎么拍?这动画片没反派怎么行?这样,工资翻倍(虽然原来只有300),给你安排新岗位:首席架构师。你给我开发一个《狗熊模拟器》!”

为了那点窝囊费……啊不,为了展现我的技术。

1.2 新工作,新需求

项目需求文档 - 《狗熊模拟器 v1.0》
甲方
:李老板
描述:模拟团结屯狗熊的习性。
功能点:冬眠、爬树、居住习惯,以及最喜欢的食物。

二. 光头强的OO天赋

看完需求,我嘴角上扬。这不就是典型的继承题吗? 既然熊大熊二都住在团结屯,除了吃的口味不同,其他行为(冬眠、爬树、住树洞)完全一致。 我决定使用继承大法,主打一个代码复用,少写一行是一行。

请添加图片描述
classBear{public:virtual std::string FavoriteFood()=0;voidHibernation(){ std::cout <<"进行冬眠"<< std::endl;}voidClimbTree(){ std::cout <<"会爬树"<< std::endl;}voidLivingHabit(){ std::cout <<"住在树洞里面"<< std::endl;}protected:};classXiongDa:publicBear{public: std::string FavoriteFood()override{return"苹果";}};classXiongEr:publicBear{public: std::string FavoriteFood()override{return"蜂蜜";}};

代码行云流水,提交Git,李老板看后直呼内行。

三. 李老板的新需求

李老板发现这个程序很有商业价值,格局打开,要把业务扩展到全宇宙的森林,不只是团结屯。

3.1 出大问题了

新增需求:系统要支持北极熊、熊猫、甚至玩具熊。

这时候我才发现,刚刚为了偷懒把 HibernationClimbTree写死在基类里,简直是在给自己挖坑!

  • 北极熊:不冬眠啊!
  • 玩具熊:人家连活物都不是,爬个鬼的树!

如果继续用继承,我只能**覆盖基类的方法了:

请添加图片描述

为了适配新物种,我必须在每个子类里重写代码。

  • 如果有100种不冬眠的熊,我就要写100遍“不冬眠”的函数?

我希望通过继承的方式来达到代码复用的目的,但是涉及到维护时,效果并不是那么好,现在代码已经完全不能进行代码的复用了。

3.2 继承可能不是答案

我痛定思痛,回想起那本C++圣经上的教诲:

设计原则:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

简单说就是:既然“怎么爬树”和“怎么冬眠”是会变的,那就把它们踢出 Bear 类,单独封装!
我要把“行为”变成一种“零件”,哪只熊需要什么零件,组装上去就行了。这就是组合
你决定将基类的方式实现进行封装起来,对代码进行重构。

现在,Bear 类不再亲自负责实现“爬树”这个动作,它只负责拥有一个“爬树行为”的接口。
具体怎么爬?让接口的实现类去操心吧!

请添加图片描述

四. 最终方案

为了代码整洁,我们专注于重构 HibernationClimbTree 这两个变化点。

  1. 先把“怎么冬眠”抽象成一个接口族:
classHibernation_Behavior{public:virtualvoidHibernation()=0;};classHibernation_able:publicHibernation_Behavior{public:voidHibernation()override{ std::cout <<"进行冬眠"<< std::endl;}};classHibernation_unable:publicHibernation_Behavior{public:voidHibernation()override{ std::cout <<"不需要冬眠"<< std::endl;}};
  1. 同理,把爬树能力也拆分出来:
classClimbTree_Behavior{public:virtualvoidClimbTree()=0;};classClimbTree_able:publicClimbTree_Behavior{public:voidClimbTree()override{ std::cout <<"会爬树"<< std::endl;}};classClimbTree_unable:publicClimbTree_Behavior{public:voidClimbTree()override{ std::cout <<"不需要爬树"<< std::endl;}};
  1. 重构 Bear 类
classBear{public:virtualvoidHibernation()=0;virtualvoidClimbTree()=0;protected: std::shared_ptr<Hibernation_Behavior> hibernation_behavior_; std::shared_ptr<ClimbTree_Behavior> climbTree_behavior_;};
  1. 各种熊的实现:
classBrownBear:publicBear{public:BrownBear(){ hibernation_behavior_ = std::make_shared<Hibernation_unable>(); climbTree_behavior_ = std::make_shared<ClimbTree_able>();}voidHibernation(){ hibernation_behavior_->Hibernation();}voidClimbTree(){ climbTree_behavior_->ClimbTree();}};classPanda:publicBear{public:Panda(){ hibernation_behavior_ = std::make_shared<Hibernation_unable>(); climbTree_behavior_ = std::make_shared<ClimbTree_able>();}voidHibernation(){ hibernation_behavior_->Hibernation();}voidClimbTree(){ climbTree_behavior_->ClimbTree();}};

五. 总结

这就是传说中的策略模式(Strategy Pattern)

通过把 Hibernation_BehaviorClimbTree_Behavior 定义为算法族,我们将行为的实现与使用行为的 Bear 类彻底解耦。

好处显而易见:

  1. 复用性起飞:如果不冬眠的代码逻辑变了,我只需要改 Hibernation_unable 这一个类,所有不冬眠的熊都会自动更新。
  2. 扩展性无敌:李老板要是让我加个“机械熊”,我只需要新写一个 RocketJump_Behavior,然后在机械熊里装配上就行,根本不用去动原来的代码。
最后策略模式定义就是: 定义算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

好了,代码写完了,李老板对此非常满意,决定再奖励我加班修Bug。我要去砍树…啊不,去Debug了,下期见!

Read more

【算法通关指南:数据结构与算法篇】二叉树相关算法题:1.二叉树深度 2.求先序排列

【算法通关指南:数据结构与算法篇】二叉树相关算法题:1.二叉树深度 2.求先序排列

🔥小龙报:个人主页 🎬作者简介:C++研发,嵌入式,机器人方向学习者 ❄️个人专栏:《算法通关指南》 ✨ 永远相信美好的事情即将发生 文章目录 * 前言 * 一、二叉树深度 * 2.1题目 * 2.2 算法原理 * 2.3代码 * 二、 求先序排列 * 3.1题目 * 3.2 算法原理 * 3.3代码 * 总结与每日励志 前言 本专栏聚焦算法题实战,系统讲解算法模块:以《c++编程》,《数据结构和算法》《基础算法》《算法实战》 等几个板块以题带点,讲解思路与代码实现,帮助大家快速提升代码能力ps:本章节题目分两部分,比较基础笔者只附上代码供大家参考,其他的笔者会附上自己的思考和讲解,希望和大家一起努力见证自己的算法成长 一、二叉树深度 2.

By Ne0inhk
【狂热算法篇】完全背包异次元冒险:容量魔法觉醒,价值风暴来袭!

【狂热算法篇】完全背包异次元冒险:容量魔法觉醒,价值风暴来袭!

欢迎拜访:羑悻的小杀马特.-ZEEKLOG博客 本篇主题:轻轻松松拿捏完全背包问题呀!!! 制作日期:2026.03.04 隶属专栏:美妙的算法世界 目录 一·问题定义: 二·具体问题演示:  三·动态规划解答完全背包: 3.1非装满状态: 3.1.1状态定义: 3.1.2状态转移方程:   3.1.3初始化: 3.1.4返回值: 3.1.5填充dp表: 3.1.6非装满状态代码总结: 3.1.7非装满状态滚动数组降维优化:  3.2装满状态: 3.2.1状态定义: 3.2.2状态转移方程:  3.

By Ne0inhk
[python]-多任务

[python]-多任务

介绍 多任务的优势 多个任务同时执行能够充分利用CPU资源,大大提高程序执行效率 1. 思考一下: 利用现学知识能够让多个任务同时执行吗? 不能,因为之前所写的程序都是单任务的,也就是说一个函数或者方法执行完成,另外一个函数或者方法才能执行,要想实现多个任务同时执行就需要使用多任务。 概念 多任务是指在同一时间内执行多个任务(给我们的感觉)。 1. 例如: 现在电脑安装的操作系统都是多任务操作系统,可以同时运行着多个软件。 1. 多任务的两种表现形式 * 并发: 在一段时间内,交替执行任务 * 并行: 在一段时间内,真正的同时一起执行多个任务 进程 进程的概念 进程(Process)是CPU资源分配的最小单位,它是操作系统进行资源分配和调度运行的基本单位 通俗理解: 一个正在运行的程序就是一个进程. 例如: 正在运行的qq,微信等他们都是一个进程 注意: 一个程序运行后至少有一个进程 多进程的作用 图中是一个非常简单的程序, 1. 一旦运行hello.py这个程序,按照代码的执行顺序, 2. func_a函数执行完

By Ne0inhk
基于Python大数据旅游数据分析与推荐系统的爬虫 数据分析可视化系统

基于Python大数据旅游数据分析与推荐系统的爬虫 数据分析可视化系统

文章目录 * 摘要 * 技术亮点 * 项目简介 * 大数据系统开发流程 * 主要运用技术介绍 * 爬虫核心代码展示 * 结论 * 源码文档获取定制开发/同行可拿货,招校园代理 :文章底部获取博主联系方式! 摘要 该系统基于Python技术栈构建,整合了网络爬虫、大数据分析、机器学习推荐算法及可视化技术,旨在为旅游行业提供数据驱动的决策支持与个性化服务。 数据采集层采用Scrapy框架爬取主流旅游平台(如携程、TripAdvisor)的多维数据,包括景点信息、用户评论、价格动态及地理位置,通过反爬策略(动态IP代理、请求头模拟)确保数据完整性。数据存储使用MongoDB处理非结构化文本,MySQL管理结构化属性字段。 数据分析层基于Pandas与NumPy进行数据清洗(缺失值填充、异常值剔除)和特征工程(情感分析、热度指数计算)。结合PySpark实现分布式处理,对海量用户行为日志进行聚类分析(K-Means)与关联规则挖掘(Apriori算法),识别游客偏好与消费模式。 推荐系统层采用协同过滤(Surprise库)与内容推荐(TF-IDF向

By Ne0inhk