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

设计模式:1. 策略模式

笔者目前正在阅读《Head First设计模式》,首先对该书发表我的个人观点,非常有趣生动的一本书,在阅读这本书之前,我一直对设计模式抱有畏惧的心理,阅读该书之后,才发现设计模式可以这么通俗易懂,推荐各位去阅读原书。为加深知识印象,对书中内容进行梳理总结,书中的案例均由Java实现,而笔者本人目前主要使用C++,因此该文章通过C++来描述案例。由于本人水平有限,表达会有欠佳处,若要深入理解设计模式,还是推荐读者能够阅读原书。

先设想一个场景,你所在的公司做出的一款模拟鸭子的游戏,游戏中的鸭子可以一边戏水一边呱呱叫,并且系统使用了标准的面向对象技术。设计一个超类Duck

class Duck
{
public:virtual void quack(){std::cout << "嘎嘎叫~" << std::endl;}virtual void swim(){std::cout << "游泳" << std::endl;}virtual void display() = 0; // 鸭子外观
};

并让各种鸭子都继承此超类。

class MallardDuck: public Duck // 绿头鸭
{
public:void display() override{std::cout << "绿头"  << std::endl;}
};
/* ----------------------- */
class RedheadDark: public Duck // 红头鸭
{
public:void display() override{std::cout << "红头"  << std::endl;}
};

为了提升产品竞争力,老板给你提出了新的需求,要鸭子能够飞起来。
你拍着胸部应下,简单,我只要给超类Duck类中增加一个fly()函数就可以了。

class Duck
{
public:virtual void quack(){std::cout << "嘎嘎叫~" << std::endl;}virtual void swim(){std::cout << "游泳" << std::endl;}virtual void fly(){std::cout << "飞行" << std::endl;}virtual void display() = 0; // 鸭子外观
};

可是糟糕的事情发生了,第二天老板就找到了你,“那些天空中飞来飞去的橡皮鸭 是怎么回事?”。
看样子简单地在超类中进行函数的具体实现是不合适的,不同的子类对于同一个接口可能有着不同的表现形式。如橡皮鸭不会飞,而且橡皮鸭不会嘎嘎叫,而是吱吱叫。
那如果重写超类中的函数呢?

class RubberDuck: public Duck //橡皮鸭
{
public:void quack() override{std::cout << "吱吱叫" << std::endl;}void fly() override{// 什么都不做}// .....
};

这样虽然能解决掉Bug,但是会有如下的缺点,系统难以维护。

  1. 代码会在多个子类中重复,如增加了一个诱饵鸭,它也不会飞,那么诱饵鸭也要重写fly()函数。而且如果后期对飞行动作做了优化,那么这些重复的代码也要挨个进行修改。
  2. 我们很难梳理清楚,鸭子的行为都有哪些。“吱吱叫”、“嘎嘎叫”,这些行为都在子类中维护,要一个个打开子类的文件才能查看得到。
  3. 没有办法动态的改变子类的行为,比如游戏中,给橡皮鸭背上了火箭背包,橡皮鸭应该可以飞起来了。
  4. 因为继承了具体的类,改变会牵一发动全身,造成其他鸭子不想要的改变。

接下来就要引出本次需要介绍的设计模式:策略模式
在程序设计时,我们需要尽可能遵循一个原则:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
在这个例子中,变化的部分就是鸭子的行为。我们把行为抽离出来,组成一组新类来表示每个行为。
再补充一个设计原则:针对接口编程,而不是针对实现编程。
我们可以定义一个接口,来表示鸭子的飞行行为。

class FlyBehavior
{
public:virtual void fly() = 0;
};

每一个具体的行为,都是对这个接口的实现。

class FlyWithWings: public FlyBehavior
{
public:void fly() override{std::cout << "使用翅膀飞行~" << std::endl;}
};
class FlyNoWay: public FlyBehavior
{
public:void fly() override{std::cout << "不会飞行~" << std::endl;}
};

这时候,我们再对Duck类进行如下修改。

class Duck
{
// 其他行为暂时省略,这里关注飞行行为。
public:Duck(FlyBehavior* fb):flyBehavior(fb){}void performFly(){flyBehavior->fly();}void setFlyBehavior(FlyBehavior* fb){flyBehavior = fb;}
private:FlyBehavior* flyBehavior;
};

橡皮鸭RubberDuck这么写。

class RubberDuck: public Duck
{
public:RubberDuck(FlyBehavior* fb):Duck(fb) {}
};

业务流程这么写。

int main()
{FlyBehavior* flyNoWay = new FlyNoWay(); // 创建行为对象Duck* rubberDuck = new RubberDuck(flyNoWay); // 创建鸭子对象,并绑定行为rubberDuck->performFly(); // 由行为对象代理执行动作,不会飞行FlyBehavior* flyByRocket = new FlyRocketPowered(); //创建一个“火箭背包飞行”的行为对象rubberDuck->setFlyBehavior(flyByRocket); // 现在橡皮鸭可以通过火箭背包飞行了rubberDuck->performFly(); // 起飞
}

可以看到,使用策略模式,不仅实现了动态更换行为。而且,如果要扩展新的行为需求,只需要新建一个类继承FlyBehavior接口,不需要更改原有代码。且鸭子共有哪些行为,也可以通过哪些类继承了Behavior接口快速找到,方便系统的维护。
最后,给出策略模式的定义:
定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

http://www.gsyq.cn/news/1519648.html

相关文章:

  • 桨影翻飞绘长卷,龙舟赛传承千年端午文脉 - 资讯速览
  • 【模型架构篇11】多模态架构:视觉-语言融合深度解析
  • 深入解析NXP KE1x MCU:Cortex-M0+内核与SIM模块实战配置指南
  • MC9328MXS USB设备控制器:从寄存器配置到数据传输实战
  • 【科研快报】与其消灭AI幻觉,不如教它说“我不确定“——谷歌团队提出AI元认知新范式
  • 揭阳亲测!汽车贴膜品牌老店推荐首推揭阳市榕城区东升志明汽车用品 - 资讯速览
  • “提示词”根本不算技能!程序员真正靠AI赚钱的3个硬核误区揭秘
  • 告别手动制表:3种办公场景下的效率工具选择思路 - 品牌测评鉴赏家
  • 开发日志(十一):多模态菜单 RAG 系统实战
  • 26年春季学期学习记录第44天
  • 鸿蒙数学108篇 第八十二篇:微积分基本定理
  • 猫抓浏览器扩展终极指南:三步搞定网页视频音频下载
  • 星露谷物语SMAPI终极指南:5分钟学会安全安装模组框架
  • Maya glTF导出插件深度解析:构建高效3D格式转换工作流实战指南
  • 2026无锡瓷砖空鼓翘边拱起根治全攻略|苏易修缮本地工况专属修复指南 - 苏易修缮
  • 3步掌握Kazumi硬件解码优化:告别手机视频卡顿的终极指南
  • 2026年张家港二手手机店大起底:这家企业为何脱颖而出? - 资讯速览
  • 2026年6月超声波点焊机直销工厂哪家专业,炭包超声波封口机/手提袋超声波点焊机,超声波点焊机源头工厂哪家专业 - 品牌推荐师
  • 表格自动化哪个工具好用?三款主流办公工具实测解析,适配全办公场景 - 品牌测评鉴赏家
  • WebPlotDigitizer:从图表图像中提取科研数据的智能助手
  • M68HC05指令集深度解析:从CISC架构到嵌入式实战优化
  • 会议视频快速转文字、提取音频!2026超好用工具实测 - 品牌测评鉴赏家
  • M68HC05微控制器核心概念:从指令集到内存映射的实战解析
  • Motorola Suite56并口JTAG调试器:原理、接口设计与实战排障
  • 2026年5月亲测东莞老店音响效果首推东莞洪浪汽车音响 - 资讯速览
  • 从‘死神经元’到稳定训练:在ResNet和Transformer里用PyTorch的LeakyReLU替代ReLU的实操指南
  • zhihu-api技术解析:构建高效知乎数据采集方案
  • CGAL泊松重建实战:从点云到网格,手把手教你用C++代码跑通第一个3D模型
  • MCU内部RC振荡器频率校准与时钟源切换实战指南
  • 别再只盯着算力了!深入拆解大模型训练中的‘通信墙’:NVLink、PCIe与网络拓扑实战分析