在游戏开发中,我们经常会遇到这样一种情况:
同一类行为在执行流程上是完全一致的,但在某几个细节步骤上又存在差异。
比如角色攻击流程,无论是普通攻击还是氪金技能,整体顺序基本都是:播放动画、播放音效、进行伤害计算、播放特效。真正不同的,其实只有某些具体实现细节。
如果每种攻击都单独写一套完整逻辑,不仅代码重复严重,一旦流程发生调整,还需要到处修改,维护成本非常高。
这类"流程固定、细节可变 "的问题,非常适合使用模板方法模式来解决。
接下来,我将通过一个简单的攻击技能示例,演示如何在 Unity 中使用模板方法模式,既保证攻击流程的统一,又能灵活扩展不同技能的表现效果。
1.定义攻击模板
我们将固定不变的操作给它写死,把那些不同的方法写成抽象方法,之后具体的技能去实现抽象方法,然后调用的时候使用Atk方法就能自动执行这一套逻辑了。
cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class AttackTemplate
{
public void Atk()
{
AtkAni();
AtkSound();
DamageCalc();
PlaySpecialeffects();
}
//攻击动画
void AtkAni()
{
Debug.Log("播放攻击动画");
}
//攻击音效
void AtkSound()
{
Debug.Log("播放攻击音效");
}
//伤害计算
void DamageCalc()
{
Debug.Log("伤害计算");
}
//游戏特效不同技能不同抽象方法
protected abstract void PlaySpecialeffects();
}
2.实现具体攻击方法
普通玩家的技能,实现播放普通特效。
cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class OrdinarySkill : AttackTemplate
{
protected override void PlaySpecialeffects()
{
Debug.Log("普通玩家普通特效");
}
}
氪金玩家播放氪金特效
cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class KryptongoldSkill : AttackTemplate
{
protected override void PlaySpecialeffects()
{
Debug.Log("氪金玩家的绚丽特效");
}
}
3.使用
通过模板的方式调用,这里为了演示方便写在了Updata里面,实际情况是在初始化的时候就创建好了,这里请注意。
cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
void Update()
{
if (Input.GetKeyDown(KeyCode.P))
{
AttackTemplate template = new OrdinarySkill();
template.Atk();
}
if (Input.GetKeyDown(KeyCode.K))
{
AttackTemplate template = new KryptongoldSkill();
template.Atk();
}
}
}
4.运行结果
将Player脚本加到场景中的一个空对象上然后运行游戏,可以看到按下"P"键和按下"K"键都打印了一套流程只是最后的特效不同。


5.总结
通过这个攻击技能的示例可以看出,模板方法模式的核心价值并不在于"设计模式本身",而在于对变化点的正确拆分 。
父类负责定义稳定且不可被随意修改的执行流程,而子类只需要关注各自不同的实现细节,这样既保证了逻辑一致性,又提升了系统的可扩展性。
在实际的游戏开发中,模板方法模式非常适合用于攻击流程、怪物 AI 行为、任务执行流程、关卡结算流程等场景。当你发现多个逻辑拥有相同的执行顺序,只是某几个步骤不同的时候,就可以考虑引入模板方法模式来重构代码。
合理使用设计模式的关键并不是"套模板",而是让代码结构更加清晰、可维护。当你能自然地把它们融入到具体业务中时,设计模式才真正发挥了它应有的价值。