文章目录
-
-
- [📜 解释器模式(Interpreter Pattern)深度解析](#📜 解释器模式(Interpreter Pattern)深度解析)
-
- 一、模式本质与核心价值
- 二、经典UML结构
- 三、Unity实战代码(技能伤害计算系统)
-
- [1. 定义表达式接口与上下文](#1. 定义表达式接口与上下文)
- [2. 实现基础表达式](#2. 实现基础表达式)
- [3. 构建语法解析器](#3. 构建语法解析器)
- [4. 客户端使用](#4. 客户端使用)
- 四、模式进阶技巧
-
- [1. 语法树优化](#1. 语法树优化)
- [2. 条件表达式](#2. 条件表达式)
- [3. 自定义函数支持](#3. 自定义函数支持)
- 五、游戏开发典型应用场景
- 六、性能优化策略
- 七、模式对比与选择
- 八、最佳实践原则
- 九、常见问题解决方案
-
📜 解释器模式(Interpreter Pattern)深度解析
------以Unity实现动态技能公式 与自定义条件系统为核心案例
一、模式本质与核心价值
核心目标 :
✅ 定义语言的文法 ,并构建解释器 执行表达式
✅ 灵活扩展语法规则 ,支持自定义DSL(领域特定语言)
✅ 解耦语法解析与执行,提升系统可维护性
关键术语:
- AbstractExpression(抽象表达式):定义解释操作的接口
- TerminalExpression(终结符表达式):语法中的基础元素
- NonterminalExpression(非终结符表达式):组合其他表达式的复合元素
- Context(上下文):存储解释器全局信息
数学表达 :
对于文法G,解释器I满足:
I(E) = Value
其中E为表达式,Value为执行结果
二、经典UML结构
<<interface>> IExpression +Interpret(context: GameContext) : int NumberExpression -value: int +Interpret() AddExpression -left: IExpression -right: IExpression +Interpret() SkillDamageExpression +Interpret()
三、Unity实战代码(技能伤害计算系统)
1. 定义表达式接口与上下文
csharp
public interface ISkillExpression {
float Interpret(SkillContext context);
}
public class SkillContext {
public GameObject Caster;
public GameObject Target;
public int SkillLevel;
public Dictionary<string, float> Variables = new();
}
2. 实现基础表达式
csharp
// 终结符:常数值
public class ConstantExpr : ISkillExpression {
private float _value;
public ConstantExpr(float value) => _value = value;
public float Interpret(SkillContext context) => _value;
}
// 终结符:获取角色属性
public class AttributeExpr : ISkillExpression {
private string _attrName;
public AttributeExpr(string attrName) => _attrName = attrName;
public float Interpret(SkillContext context) {
return context.Caster.GetComponent<CharacterStats>()
.GetAttribute(_attrName);
}
}
// 非终结符:加法运算
public class AddExpr : ISkillExpression {
private ISkillExpression _left;
private ISkillExpression _right;
public AddExpr(ISkillExpression left, ISkillExpression right) {
_left = left;
_right = right;
}
public float Interpret(SkillContext context) {
return _left.Interpret(context) + _right.Interpret(context);
}
}
3. 构建语法解析器
csharp
public class SkillParser {
public ISkillExpression Parse(string formula) {
// 示例:解析 "ATK * 2 + SKILL_LV * 5"
var tokens = Tokenize(formula);
return ParseAdditive(tokens);
}
private Queue<string> Tokenize(string input) {
// 实现分词逻辑(此处简化)
return new Queue<string>(input.Split(' '));
}
private ISkillExpression ParseAdditive(Queue<string> tokens) {
ISkillExpression left = ParseMultiplicative(tokens);
while(tokens.Count > 0 && (tokens.Peek() == "+" || tokens.Peek() == "-")) {
string op = tokens.Dequeue();
ISkillExpression right = ParseMultiplicative(tokens);
left = op == "+" ? new AddExpr(left, right) : new SubtractExpr(left, right);
}
return left;
}
private ISkillExpression ParseMultiplicative(Queue<string> tokens) {
// 类似实现乘法/除法解析
}
}
4. 客户端使用
csharp
public class SkillSystem : MonoBehaviour {
private Dictionary<string, ISkillExpression> _skillFormulas = new();
void Start() {
// 预编译技能公式
var parser = new SkillParser();
_skillFormulas["Fireball"] = parser.Parse("ATK * 1.5 + INT * 2");
_skillFormulas["Heal"] = parser.Parse("(WIS * 3) + (SKILL_LV * 10)");
}
public float CalculateDamage(string skillName, SkillContext context) {
return _skillFormulas[skillName].Interpret(context);
}
}
四、模式进阶技巧
1. 语法树优化
csharp
public class CachedExpression : ISkillExpression {
private float? _cache;
private ISkillExpression _expr;
public float Interpret(SkillContext context) {
return _cache ??= _expr.Interpret(context);
}
}
2. 条件表达式
csharp
public class ConditionExpr : ISkillExpression {
private ISkillExpression _condition;
private ISkillExpression _trueExpr;
private ISkillExpression _falseExpr;
public float Interpret(SkillContext context) {
bool result = _condition.Interpret(context) > 0;
return result ? _trueExpr.Interpret(context)
: _falseExpr.Interpret(context);
}
}
3. 自定义函数支持
csharp
public class FunctionExpr : ISkillExpression {
private Func<SkillContext, float> _func;
public float Interpret(SkillContext context) => _func(context);
}
五、游戏开发典型应用场景
-
技能伤害公式系统
csharp// 公式示例:"BASE_DAMAGE + (STR * 0.8) + (WEAPON_ATK * 1.2)" public class DamageCalculator { private ISkillExpression _damageFormula; public void SetFormula(string expr) { _damageFormula = new SkillParser().Parse(expr); } }
-
对话条件系统
csharppublic class DialogueCondition { private ISkillExpression _condition; public bool IsMet(GameState state) { return _condition.Interpret(state) > 0; } }
-
AI行为决策树
csharppublic class BehaviorTree { private ISkillExpression _decisionExpr; public AIAction DecideAction(AIContext context) { float value = _decisionExpr.Interpret(context); return value > 0.5f ? new AttackAction() : new DefendAction(); } }
-
成就解锁条件
csharppublic class AchievementCondition { // 示例条件:"PLAYER_LEVEL > 10 && COMPLETED_QUESTS >= 5" public bool Check(PlayerStats stats) { return _conditionExpr.Interpret(stats.ToContext()) > 0; } }
六、性能优化策略
策略 | 实现方式 | 适用场景 |
---|---|---|
预编译表达式 | 提前构建语法树 | 频繁使用的公式 |
字节码转换 | 转换为中间指令 | 复杂表达式 |
记忆化缓存 | 存储计算结果 | 重复参数调用 |
JIT编译 | 动态生成C#代码 | 超高性能需求 |
七、模式对比与选择
维度 | 解释器模式 | 策略模式 |
---|---|---|
关注点 | 语法解析 | 算法选择 |
扩展性 | 通过新增表达式类扩展 | 通过新增策略类扩展 |
复杂度 | 较高(需处理语法树) | 较低 |
典型场景 | DSL解析 | 运行时算法切换 |
八、最佳实践原则
-
限制语法复杂度:避免实现完整编程语言
-
防御式解析 :
csharpprivate ISkillExpression ParseTerm(Queue<string> tokens) { if(!tokens.Any()) throw new SyntaxException("Unexpected end of input"); // 继续解析... }
-
上下文隔离:每个解释器实例使用独立上下文
-
安全类型转换 :
csharpif(expr is AddExpr addExpr) { // 安全处理加法表达式 }
九、常见问题解决方案
Q1:如何处理语法错误?
→ 实现详细错误报告
csharp
public class SyntaxException : Exception {
public int Position { get; }
public string ReceivedToken { get; }
public SyntaxException(string message, int pos, string token)
: base($"{message} at position {pos} (token: '{token}')") {
Position = pos;
ReceivedToken = token;
}
}
Q2:如何优化深层递归性能?
→ 改用迭代解释器模式
csharp
public class IterativeInterpreter {
public float Evaluate(ISkillExpression expr, SkillContext context) {
var stack = new Stack<float>();
var evalStack = new Stack<ISkillExpression>();
evalStack.Push(expr);
while(evalStack.Count > 0) {
var current = evalStack.Pop();
if(current is TerminalExpr term) {
stack.Push(term.Interpret(context));
} else if(current is BinaryExpr bin) {
evalStack.Push(bin.Right);
evalStack.Push(bin.Left);
// 后续处理操作符...
}
}
return stack.Pop();
}
}
Q3:如何实现变量赋值?
→ 扩展上下文支持
csharp
public class AssignExpr : ISkillExpression {
private string _varName;
private ISkillExpression _valueExpr;
public float Interpret(SkillContext context) {
float value = _valueExpr.Interpret(context);
context.Variables[_varName] = value;
return value;
}
}
上一篇 【行为型之命令模式】游戏开发实战------Unity可撤销系统与高级输入管理的架构秘钥
下一篇 【行为型之迭代器模式】游戏开发实战------Unity高效集合遍历与场景管理的架构精髓