模块方法模式是一种行为型设计模式. 它的核心思想是: 定义一个操作的骨架流程, 将一些步骤的具体实现延迟到子类中. 这样, 子类可以在不改变流程结构的前提下, 重新定义流程中的某些特定步骤.
 
一个生动的比喻是: 做菜的食谱.
  • 具体步骤
    • 不变的步骤:有些步骤是通用的,比如 “装盘”。
    • 可变的步骤:有些步骤则根据具体做什么菜而变化。例如,“准备食材” 和 “烹饪” 步骤,做 “西红柿炒鸡蛋” 和做 “红烧肉” 的做法完全不同。
 
在这个比喻中, 食谱 就是抽象基类, 西红柿炒蛋红烧肉 就是具体的子类. 子类继承了食谱的整体流程, 但重写了”准备食材”和”烹饪”等方法来实现自己的特色.

Unity中的例子: 角色技能释放流程

假设我们正在开发一个RPG游戏, 角色有多种技能, 每种技能的释放都遵循一个相似的通用流程, 但某些环境的具体表现不同.
 

通用流程(模板方法):

  1. 检查条件: 检查角色是否满足释放技能的条件(如: 法力值是否足够\是否处于冷却中\是否在硬直状态等)
  1. 消耗资源: 如果条件满足, 消耗相应的法力值(MP)或其他资源.
  1. 播放动画: 播放技能释放的动画.
  1. 执行技能效果: 这是最核心的部分, 比如发射一个火球\治疗自己或队友\增加一个增益buff等.
  1. 开始冷却: 技能释放后, 开始进入冷却时间
  1. 播放音效/特效: 播放技能相关的音效和视觉特效
 
这里, 步骤1\2\5\6对于所有技能来说, 逻辑可能都是相同的或高度相似的. 而步骤3(播放什么动画)和步骤4(具体什么效果)则是每种技能独有的.

使用模板方法模式来实现

步骤1: 创建抽象基类(定义模板)
我们创建一个名为 Skill 的抽象类. 他将定义技能释放的整个流程(模板方法), 并将可变的步骤声明为抽象方法, 留给子类去实现
 
步骤2: 创建具体子类(实现可变步骤)
现在, 我们来创建两个具体的技能: FireballSkill(火球术)和HealSkill(治愈术). 它们将继承自Skill 并实现抽象方法.
 
步骤3: 在unity中使用
我们需要一个 PlayerController 来管理技能的切换和释放
 

模板方法模式的优点

  1. 代码复用: 将所有技能的公共流程(如检查条件\消耗资源\冷却)封装在基类Skill 中, 避免了代码重复.
  1. 行为扩展: 新的技能只需要创建一个新的子类, 并实现 PlayerCastAnimationExecuteSkillEffect 两个抽象方法即可. 无需修改现有代码, 符合开放/封闭原则.
  1. 流程控制: 基类牢牢控制着整个金额能释放的流程骨架, 子类无法改变这个流程, 只能填充细节, 保证了程序的稳定性和一致性.
  1. 易于维护: 当需要修改公共流程(比如, 所有技能释放前都要播放一个通用的准备动作)时, 只需要修改基类 SkillCastSkill 方法即可, 所有子类都会自动受益.
 

在Unity中的其他应用场景

  • 敌人AI行为: 定义一个EnemyAI 基类, 包含 UpdateAI() 模板方法, 流程可能是 CheckEnvironment() → DecideAction() → ExecuteAction() . 不同类型的敌人(如近战\远程\BOSS)可以继承它, 并重写 DecideAction()ExecuteAction() 来实现不同的行为模式
  • 物品使用流程: 所有可使用物品都有一个通用的使用流程:CheckCanUse() → ConsumeItem() → ApplyEffect()。具体的效果(如加血、加 buff、打开门)由子类实现。
  • UI 界面切换:定义一个 UIScreen 基类,模板方法 Show() 可能包含 FadeIn() → LoadContent() → RegisterEvents()。不同的界面(主菜单、设置、商店)继承它,重写 LoadContent() 来加载自己的 UI 元素。
  • 动画播放控制:对于复杂的动画序列(如角色出生、死亡、胜利), 可以用模板方法来控制动画的播放顺序和时机, 子类可以定制某些关键帧的特效或回调.
模板方法模式非常适合用于那些具有固定流程但可变细节的场景,它能极大地提高代码的复用性和可维护性.