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

第二章 设计模式故事会之策略模式:魔王城里的勇者传说

系列文章目录

第一章 设计模式故事会之楔子:面试还在回答策略、工厂?该升级设计模式库了!
第二章 设计模式故事会之策略模式:魔王城里的勇者传说


文章目录

  • 系列文章目录
  • 🏰魔王城里的勇者传说
  • 🎭 **彩蛋片尾**
  • 🤔小A的思考
      • 第一次尝试:继承带来的问题
      • 第二次尝试:组合与策略模式的雏形
      • 决战时刻:策略模式的终极应用
      • 策略模式消除`if...else`
  • 😩林克的烦恼
  • 总结
  • 附录
      • 第一阶段:硬编码的困境
      • 第二阶段:继承带来的“类爆炸”
      • 第三阶段:策略模式——组合优于继承


🏰魔王城里的勇者传说

    很久很久以前,魔王抓走了公主,以此威胁国王。为了拯救公主,勇者林克带上了村里最好的剑,踏上了讨伐魔王的征途。。。

    一路上,出现了各种奇奇怪怪的怪物。林克抄起剑就砍,过关斩将并不是什么难事。林克心里不禁暗想:这些怪物真是逊啊,这样下去,要不了多久就能救出公主了

    行不多时,空气逐渐变得灼热了起来,他遇到一个 火焰守卫。这守卫全身冒火,像个移动的火炉。林克依旧举剑就砍,但剑刚碰到守卫,就被烧得通红,根本无法近身。林克心里一凉,在这么整下去,他迟早被烤熟,惹不起还躲不起吗?换路总行了吧

    避开了 火焰守卫,林克继续前进,炎热逐渐散去,取而代之的是刺骨的寒冷,林克被冻得直哆嗦。不久,眼前出现一个浑身冒着寒气的 冰霜守卫。得!一看就是惹不起的主,都还没靠近,剑身已经结满冰霜,变得又脆又重。林克脸都绿了,转头就走:这还怎么玩,溜了溜了!!

    “傻小子,对付不同的怪物要用不同的剑,你那把剑只能打打普通的怪。。。属性剑就在城堡的入口。” 忽然,一个苍老的声音想起

    “老头,你这不早点说,害我在这又被烤又被冻的?”林克满脸不爽的回答,脚下丝毫不停,继续狂奔

    “你自己爱跳新手教程,还怨我,别啰嗦了,想活命就快点去拿装备吧。” 苍老的声音渐渐弱了下来,随后彻底消失

    林克骂骂咧咧的回到门口,果真发现几把剑:霜之哀伤、火之高兴、木之乃伊。回想起差点把他烤熟的火焰守卫,林克一阵牙痒痒,拿起霜之哀伤就杀回去。有了属性加持,林克非但没感觉到热还有一丝丝冰凉,一剑挥出,寒意四起。属相相克打出暴击,一下子就消灭了火焰守卫

    接下来,林克如法炮制,解决了冰霜守卫,一路上一会儿冰,一会儿火,一会儿电。林克就这么往返跑,遇到哪种守卫,就去门口拿对应的属性剑。开始林克还没感觉,渐渐的体力有点不支。路程还没过半,林克已经开始喘粗气了,这么来回倒腾,没被怪打死,自己先得活活累死。遇到新的怪物,还得重新制作一把新剑。着实麻烦。不行,得想个法子。林克回到了门口,仔细扫视了地上的的东西,发现之前没有注意的东西——元素宝石。这玩意可以和普通剑结合,产生属性剑的效果。这就简单了,林克摸了几个不同属性的宝石,提溜上村里最好的剑再次踏上了征程。这次,林克从容不迫,遇到火焰守卫,就换上冰霜宝石;遇到冰霜守卫,就换上火焰宝石。他再也不用像个傻子一样来回跑了。

    随着怪物一个个倒下,林克已经到达大魔王面前,决战即将到来!!

    “林克,你来了。。百年前,海拉鲁大陆。。” 出乎意料,大战并没有一触即发,魔王反而饶有兴致的讲起故事

    有破绽!!!霎那间,剑气纵横,寒意凛冽。林克上来就是一套小连招,附带冰元素剑气全都砍向了魔王

    魔王从容不迫,没有任何动作。交错的剑气在魔王身前不断湮灭,他继续开始讲起了故事:“你小子,能不能听人把话说完!!!百年前。。。”

    “冰元素无效?!”林克愕然,魔王依旧喋喋不休的讲着故事,林克换上火元素继续出击。这次,热浪滚滚,剑尖吞吐着火舌,似欲焚尽九天

    剑气依旧在魔王面前消失,火元素也没用!!不过魔王似乎有点恼火,对着旁边怒道:“导演!!这故事非讲不可吗?这个愣头青一点也不听,就在那钻空砍我!!!!”

    “克服克服,魔王同志,不要总是抱怨,找找自己的原因!” 导演摆弄着摄像机,侧头说到

    “*%@#!”魔王忍不住骂娘,心里诅咒。就在他说话的空隙,林克又出了好几次手,他得反击了,不然要被砍死了。。。

    林克抖了抖背包,所有元素都无效?!这要怎么玩!!!倒不是林克不想跑,实在是因为房间被下了结界,没法跑

    似乎看出可林克的窘境,魔王发出了爽朗的笑声:“哈哈哈哈,蠢货!褶子了吧,没招了吧!我是暗属性。。桀桀桀。那就从世界上消失吧。” 言讫,魔王开始读条,准备放大招

    就在这千钧一发之际,林克突然想起城堡入口的刻字:“每一个石头都有无尽可能?!”

    林克拿出了背包里的一块普通石头,迅速地用魔法符文在上面刻画。在魔王读条的过程中,一块圣光宝石诞生了

    当林克把这颗新宝石插进剑时,剑身发出了耀眼的光芒,轻易地击溃了魔王,救出了公主。从此勇者和公主过上了幸福的生活。。。

在这里插入图片描述

🎭 彩蛋片尾

    “什么魔法符文,是你临时编的吧。” 魔王一脸鄙夷的看着导演

    “没办法,我实在想不出怎么收尾。。” 导演无奈的摊摊手

🤔小A的思考

    合上书,小A 闭上眼睛思索了一下。勇者林克在讨伐魔王的过程中,面临了几个关键的选择,这些选择恰好对应了软件设计中的不同思路

第一次尝试:继承带来的问题

    林克最初用普通剑打怪,遇到特殊怪物束手无策。后来,他拿起不同属性的剑应对不同怪物:

  • 基类:Sword(普通剑)
  • 为了处理 火焰守卫,可以继承 Sword 创建 IceSword (冰剑)
  • 为了处理 冰霜守卫,可以继承 Sword 创建 FireSword (火剑)

林克每次战斗都得回去更换整把剑。更糟的是,如果一把剑不仅有攻击能力,还有格挡、附魔、投掷等多种行为,每增加一种新元素,林克就需要打造一把全新的、包含了所有行为的毒剑或光剑。这不仅导致了类的急剧膨胀,也就是所谓的 类爆炸

第二次尝试:组合与策略模式的雏形

    林克发现元素宝石可以嵌入普通剑,动态改变攻击属性。这就是 策略模式 的雏形:

  • Context(环境角色): 勇者林克,他持有普通剑
  • Strategy(抽象策略角色): 元素宝石,表示可替换的攻击方式
  • ConcreteStrategy(具体策略角色): 冰霜宝石、火焰宝石、雷电宝石

遇到不同怪物时,只需装配不同宝石即可,无需更换整把剑。策略模式 带来的好处:

  1. 高灵活性: 快速切换策略
  2. 可扩展性: 新增策略不影响原系统

决战时刻:策略模式的终极应用

    在冰、火等宝石对魔王无效时,林克临时创造了 圣光宝石,击败魔王。这说明:

  • 策略可以动态创建
  • 运行时选择策略,而非编译时固定

策略模式消除if...else

    小A 心中的疑惑并未完全解开。他继续思考着一个困扰他已久的问题:很多 设计模式 的书籍和文章都说,策略模式 是用来消除if...else的。但林克的故事让他疑窦丛生,因为林克依然需要根据不同怪物来选择不同的宝石。这意味着不同场景下的判断和选择是必须存在的,它并没有消失啊

    小A 的思绪流转着,他意识到,也许“消除if...else”这个说法本身就不够准确。策略模式 的精髓,并非是让所有判断都消失,而是将一大坨代码从判断中剥离出来。而各自分支下的代码形成了不同的策略,if...else依旧存在,只是它不在那么的臃肿和难以阅读了。策略模式关注的是将变化部分封装起来,而不是彻底消灭分支逻辑

    当然了,一定要让if...else也行,整一个映射表,根据不同情况获取不同策略,这也许就是所谓的消灭if...else的方式了吧

😩林克的烦恼

  1. 元素宝石的出现。固然让林克省去了背着一大堆剑的麻烦,但是宝石多了,同样不好管理,林克的背包可不是无限的噢,望着一大堆的宝石,林克愁眉不展
  2. 林克嫌每次遇到怪物都要重新翻一下背包,寻找宝石太过麻烦,如何才能遇到不同的怪物时自动附上对应的宝石呢?

在这里插入图片描述

你会怎么帮助林克呢?欢迎留下你的答案。代码在最下面哦~~~~


总结

    勇者的故事着实让 小A 收益匪浅,之前 小A 以为 策略模式 就是有多个不同实现,可以替换if...else,现在看来,自己简直大错特错。策略模式 就是把类行为进行剥离,可以动态切换。并且避免 类爆炸问题

附录

第一阶段:硬编码的困境

    勇者林克一开始只用一把普通剑,遇到特殊的怪物时,攻击逻辑直接在代码里写死,导致无法应对变化

import randomclass Hero:def __init__(self, name="林克"):self.name = namedef attack(self, monster):print(f"勇者{self.name}举起普通剑,向{monster.name}砍去!")if monster.type == "火焰":print("啊!剑被烧红了,攻击无效!")elif monster.type == "冰霜":print("剑身结冰,变得又脆又重,攻击无效!")else:print("轻松过关,怪物倒下了。")class Monster:def __init__(self, name, monster_type):self.name = nameself.type = monster_type# 场景:随机生成怪物
monster_types = ["火焰", "冰霜", "普通"]
random_monster_type = random.choice(monster_types)if random_monster_type == "火焰":monster = Monster("火焰守卫", "火焰")
elif random_monster_type == "冰霜":monster = Monster("冰霜守卫", "冰霜")
else:monster = Monster("哥布林", "普通")hero = Hero()
hero.attack(monster)

第二阶段:继承带来的“类爆炸”

    林克意识到需要不同的剑,但这种“一把剑对应一种怪物”的思路,在代码中对应着继承关系

import random# 基类:普通的剑
class Sword:def attack(self, monster):return f"用普通剑攻击{monster.name},毫无作用!"# 子类:不同属性的剑,继承自Sword
class IceSword(Sword):def attack(self, monster):return f"发出冰霜剑气,轻松消灭{monster.name}!"class FireSword(Sword):def attack(self, monster):return f"喷出灼热火焰,轻松消灭{monster.name}!"# 勇者现在需要根据怪物类型更换不同的剑
class Hero:def __init__(self, name="林克"):self.name = nameself.current_sword = Sword() # 初始拿着普通剑def equip(self, new_sword):print(f"勇者{self.name}换上了{new_sword.__class__.__name__}。")self.current_sword = new_sworddef attack(self, monster):print(self.current_sword.attack(monster))class Monster:def __init__(self, name, monster_type):self.name = nameself.type = monster_type# 场景:随机生成怪物,并根据类型更换剑
monster_types = ["火焰", "冰霜"]
random_monster_type = random.choice(monster_types)if random_monster_type == "火焰":monster = Monster("火焰守卫", "火焰")sword = IceSword()
elif random_monster_type == "冰霜":monster = Monster("冰霜守卫", "冰霜")sword = FireSword()
else:# 理论上不会出现,但为了严谨monster = Monster("哥布林", "普通")sword = Sword()hero = Hero()
hero.equip(sword)
hero.attack(monster)

第三阶段:策略模式——组合优于继承

    林克找到了宝石,将攻击行为上剥离出来,实现了组合。这就是 策略模式 的核心思想

import random# 宝石策略
class Gem:def effect(self, monster):raise NotImplementedErrorclass IceGem(Gem):def effect(self, monster):return f"发出冰霜剑气,轻松消灭{monster.name}!"class FireGem(Gem):def effect(self, monster):return f"喷出灼热火焰,轻松消灭{monster.name}!"class HolyGem(Gem):def effect(self, monster):return f"圣光降临,彻底击败{monster.name}!"class Sword:def __init__(self, name="村里最好的剑"):self.name = nameself.gem = Nonedef insert_gem(self, gem):print(f"【{self.name}】镶嵌了 {gem.__class__.__name__}。")self.gem = gemdef attack(self, monster):if self.gem:print(self.gem.effect(monster))else:print(f"【{self.name}】挥舞普通攻击,砍向{monster.name}。")class Monster:def __init__(self, name, monster_type):self.name = nameself.type = monster_type# ----------------------------------------
# 方法 1:动态策略 + if 判断
# ----------------------------------------
def attack_with_if(hero_sword, gems, monster):selected_gem = Nonefor gem in gems:if monster.type == "火焰" and isinstance(gem, IceGem):selected_gem = gemelif monster.type == "冰霜" and isinstance(gem, FireGem):selected_gem = gemelif monster.type == "暗属性" and isinstance(gem, HolyGem):selected_gem = gemif not selected_gem and gems:selected_gem = gems[0]if selected_gem:hero_sword.insert_gem(selected_gem)print(f"使用 if 判断策略,准备攻击 {monster.name}")hero_sword.attack(monster)# ----------------------------------------
# 方法 2:动态策略 + 映射表
# ----------------------------------------
def attack_with_map(hero_sword, gems, monster):type_to_gem_class = {"火焰": IceGem,"冰霜": FireGem,"暗属性": HolyGem}selected_gem = Nonegem_class = type_to_gem_class.get(monster.type)for gem in gems:if gem_class and isinstance(gem, gem_class):selected_gem = gemif not selected_gem and gems:selected_gem = gems[0]if selected_gem:hero_sword.insert_gem(selected_gem)print(f"使用映射表策略,准备攻击 {monster.name}")hero_sword.attack(monster)# ----------------------------------------
# 场景测试
# ----------------------------------------
hero_sword = Sword()
gems = [IceGem(), FireGem(), HolyGem()]
monster_type = random.choice(["火焰", "冰霜", "暗属性", "普通"])
monster = Monster(f"{monster_type}守卫", monster_type)attack_with_if(hero_sword, gems, monster)
attack_with_map(hero_sword, gems, monster)
http://www.dtcms.com/a/349718.html

相关文章:

  • AcrelEMS-EDU在实践中的应用系列—“综合能源管理”
  • 2025年8月25日-8月31日(qtopengl+ue独立游戏)
  • 23种设计模式:模板方法模式与策略模式
  • vue 一键打包上传
  • 【车载开发系列】汽车零部件DV与PV试验的差异
  • 【QT/C++】实例理解类间的六大关系之组合关系(Composition)
  • 农业气象监测站:像敏锐的精灵,捕捉农业气象的每一丝变化
  • 18 继续学习
  • 【图像处理基石】基于Real-ESRGAN的实时图像超分辨率技术实现
  • 【GPT-5 与 GPT-4 的主要区别?】
  • 零基础也能写博客:cpolar简化Docsify远程发布流程
  • 基于波前编码成像系统模拟及图像复原的MATLAB实现
  • GPT5的Test-time compute(测试时计算)是什么?
  • 《C++ Primer 第五版》 initializer_list
  • 记一次 element-plus el-table-v2 表格滚动卡顿问题优化
  • Vue SFC Playground 如何正确引入 naive-ui
  • Kubernetes高可用架构设计:多Master节点部署与etcd集群运维深度指南
  • 6.3Element UI 的表单
  • Odoo 非标项目型生产行业解决方案:专业、完整、开源
  • 第十七节:高级材质 - ShaderMaterial揭秘
  • SOME/IP-SD报文中 Entry Format(条目格式)-理解笔记4
  • 从“数据孤岛”到“业财融合”,外贸订单管理ERP重构一体化逻辑
  • 将跨平台框架或游戏引擎开发的 macOS 应用上架 Mac App Store
  • springboot中操作redis的步骤
  • 6.4 Element UI 中的 <el-table> 表格组件
  • 疯狂星期四文案网第49天运营日记
  • 疯狂星期四文案网第50天运营日记
  • 渗透测试报告编写平台 | 简化和自动化渗透测试报告的生成过程。
  • JVM 与容器化部署优化:突破资源隔离的性能瓶颈
  • Ant Design for UI 选择下拉框