跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

设计模式:策略模式实现算法解耦与灵活扩展

策略模式通过将行为封装为独立接口,解决了继承导致的代码僵化问题。以 C++ 为例,展示了如何从硬编码的基类方法中抽离出可变算法,利用组合关系替代继承,实现算法族的可插拔替换,从而提升系统的扩展性与维护性。

活在当下发布于 2026/3/29更新于 2026/10/1977 浏览
设计模式:策略模式实现算法解耦与灵活扩展

设计模式:策略模式实现算法解耦与灵活扩展

请添加图片描述

一。光头强转行

1.1 团结屯的故事

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

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

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

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

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

1.2 新工作,新需求

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

二。光头强的 OO 天赋

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

请添加图片描述

class Bear {
public:
    virtual std::string FavoriteFood() = 0;
    void Hibernation() { 
        std::cout << "进行冬眠" << std::endl;
    }
    void ClimbTree() { 
        std::cout << "会爬树" << std::endl;
    }
    void LivingHabit() { 
        std::cout << "住在树洞里面" << std::endl;
    }
protected:
};

class XiongDa : public Bear {
public:
    std::string FavoriteFood() override {
        return "苹果";
    }
};

class XiongEr : public Bear {
public:
    std::string FavoriteFood() override {
        return "蜂蜜";
    }
};

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

三。李老板的新需求

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

3.1 出大问题了

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

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

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

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

请添加图片描述

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

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

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

3.2 继承可能不是答案

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

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

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

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

请添加图片描述

四。最终方案

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

首先,先把'怎么冬眠'抽象成一个接口族:

class Hibernation_Behavior {
public:
    virtual void Hibernation() = 0;
};

class Hibernation_able : public Hibernation_Behavior {
public:
    void Hibernation() override {
        std::cout << "进行冬眠" << std::endl;
    }
};

class Hibernation_unable : public Hibernation_Behavior {
public:
    void Hibernation() override {
        std::cout << "不需要冬眠" << std::endl;
    }
};

同理,把爬树能力也拆分出来:

class ClimbTree_Behavior {
public:
    virtual void ClimbTree() = 0;
};

class ClimbTree_able : public ClimbTree_Behavior {
public:
    void ClimbTree() override {
        std::cout << "会爬树" << std::endl;
    }
};

class ClimbTree_unable : public ClimbTree_Behavior {
public:
    void ClimbTree() override {
        std::cout << "不需要爬树" << std::endl;
    }
};

接下来重构 Bear 类,让它持有行为指针而不是直接实现:

class Bear {
public:
    virtual void Hibernation() = 0;
    virtual void ClimbTree() = 0;
protected:
    std::shared_ptr<Hibernation_Behavior> hibernation_behavior_;
    std::shared_ptr<ClimbTree_Behavior> climbTree_behavior_;
};

最后是各种熊的实现,根据特性装配不同的行为组件:

class BrownBear : public Bear {
public:
    BrownBear() {
        hibernation_behavior_ = std::make_shared<Hibernation_unable>();
        climbTree_behavior_ = std::make_shared<ClimbTree_able>();
    }
    void Hibernation() {
        hibernation_behavior_->Hibernation();
    }
    void ClimbTree() {
        climbTree_behavior_->ClimbTree();
    }
};

class Panda : public Bear {
public:
    Panda() {
        hibernation_behavior_ = std::make_shared<Hibernation_unable>();
        climbTree_behavior_ = std::make_shared<ClimbTree_able>();
    }
    void Hibernation() {
        hibernation_behavior_->Hibernation();
    }
    void ClimbTree() {
        climbTree_behavior_->ClimbTree();
    }
};

五。总结

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

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

好处显而易见:

  1. 复用性起飞:如果不冬眠的代码逻辑变了,我只需要改 Hibernation_unable 这一个类,所有不冬眠的熊都会自动更新。
  2. 扩展性无敌:李老板要是让我加个'机械熊',我只需要新写一个 RocketJump_Behavior,然后在机械熊里装配上就行,根本不用去动原来的代码。

最后策略模式定义就是:定义算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

好了,代码写完了,李老板对此非常满意,决定再奖励我加班修 Bug。我要去 Debug 了。

目录

  1. 设计模式:策略模式实现算法解耦与灵活扩展
  2. 一。光头强转行
  3. 1.1 团结屯的故事
  4. 1.2 新工作,新需求
  5. 二。光头强的 OO 天赋
  6. 三。李老板的新需求
  7. 3.1 出大问题了
  8. 3.2 继承可能不是答案
  9. 四。最终方案
  10. 五。总结

更多推荐文章

查看全部
  • 用好 document.querySelector 的几个基础点
  • 昇腾 NPU 部署 Llama 大模型:全流程实战与常见问题排查
  • 基于吾码低代码平台的服装 ERP 系统开发实战
  • SpringBoot + Vue 家政服务平台架构与核心实现
  • Spring MVC 快速入门:响应处理与报文格式设置
  • PyTorch 生成式人工智能:循环神经网络详解与实现
  • C++ 虚函数与纯虚函数:多态机制详解
  • 二叉树与堆的数据结构详解及 C 语言实现
  • incbin:C/C++ 二进制资源嵌入的实用方案
  • 无需复杂数学:轻松理解大模型基本原理
  • Android 实现类似朋友圈发说说功能:拍照、选图与多图上传(Retrofit2)
  • 智能量化交易系统 QuantCell:从数据收集到策略执行全流程自动化
  • 国产数据库的新机遇:电科金仓以融合技术同步全球竞争
  • 基于 YOLO 与大模型的多场景智能检测系统架构设计
  • 大模型智能体驱动的社会模拟:从个体到社会
  • 文心一言大模型本地部署与微调应用实战
  • 前端 AJAX 与 XMLHttpRequest 核心知识点及实战
  • 使用 Playwright 封装隐藏自动化特征的 Web 爬虫
  • Java 构建体育拼班系统实现课程按需匹配与资源协同
  • 从零开始构建大型语言模型:理解基础与架构

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online