解释器模式详解
概念
解释器模式(Interpreter Pattern)是一种行为型设计模式,用于定义一个语言的文法表示,并提供一个解释器来处理该语言中的语句或表达式。它可以让语法规则和解释逻辑分离,从而轻松地扩展和维护。
特点
- 分离语法和逻辑:语言的规则由语法树表示,解释逻辑由解释器实现。
- 递归调用:通常通过递归结构解析和计算语法树。
- 扩展性强:新增规则只需扩展语法树节点和解释逻辑。
适用场景
- 简单的语法规则:适用于开发简单的脚本语言、配置文件解析器等。
- 固定文法结构:需要定义一套固定文法并对其进行解析。
- 重复使用的语法解释:如表达式求值器、命令解析器。
使用案例
1. 数学表达式求值
- 场景:对表达式如
3 + 5 * (2 - 4)
进行解析和计算。 - 解决:用语法树表示表达式,并实现解释器计算结果。
2. SQL解析
- 场景:实现对SQL查询语句的解析和执行。
- 解决:构建SQL语法树并解析执行。
3. 简单脚本语言
- 场景:如游戏中配置简单行为脚本。
- 解决:为脚本语言定义文法规则和解释器。
优缺点
优点 | 缺点 |
易于扩展新规则,符合开闭原则 | 文法复杂时会导致类数量激增,难以维护 |
文法和解释逻辑分离,结构清晰 | 不适用于复杂语法,会增加系统复杂性 |
便于实现自定义语言和表达式解析 | 对效率要求高的场景不适用,性能可能较低 |
类图
C++实现
#include <iostream>
#include <string>
#include <memory>
#include <vector>
// 上下文类
class Context {
public:
std::string input;
int output = 0;
};
// 抽象表达式
class AbstractExpression {
public:
virtual ~AbstractExpression() = default;
virtual void Interpret(Context& context) = 0;
};
// 终结符表达式
class TerminalExpression : public AbstractExpression {
private:
std::string match;
public:
explicit TerminalExpression(const std::string& match) : match(match) {}
void Interpret(Context& context) override {
if (context.input.find(match) != std::string::npos) {
context.output++;
}
}
};
// 非终结符表达式
class NonTerminalExpression : public AbstractExpression {
private:
std::vector<std::unique_ptr<AbstractExpression>> expressions;
public:
void Add(std::unique_ptr<AbstractExpression> expression) {
expressions.push_back(std::move(expression));
}
void Interpret(Context& context) override {
for (auto& expression : expressions) {
expression->Interpret(context);
}
}
};
// 示例用法
int main() {
Context context{"hello world"};
NonTerminalExpression root;
root.Add(std::make_unique<TerminalExpression>("hello"));
root.Add(std::make_unique<TerminalExpression>("world"));
root.Interpret(context);
std::cout << "Matched words: " << context.output << std::endl;
return 0;
}
C#实现
using System;
using System.Collections.Generic;
// 上下文类
public class Context {
public string Input { get; set; }
public int Output { get; set; } = 0;
}
// 抽象表达式
public abstract class AbstractExpression {
public abstract void Interpret(Context context);
}
// 终结符表达式
public class TerminalExpression : AbstractExpression {
private readonly string _match;
public TerminalExpression(string match) {
_match = match;
}
public override void Interpret(Context context) {
if (context.Input.Contains(_match)) {
context.Output++;
}
}
}
// 非终结符表达式
public class NonTerminalExpression : AbstractExpression {
private readonly List<AbstractExpression> _expressions = new();
public void Add(AbstractExpression expression) {
_expressions.Add(expression);
}
public override void Interpret(Context context) {
foreach (var expression in _expressions) {
expression.Interpret(context);
}
}
}
// 示例用法
class Program {
static void Main(string[] args) {
var context = new Context { Input = "hello world" };
var root = new NonTerminalExpression();
root.Add(new TerminalExpression("hello"));
root.Add(new TerminalExpression("world"));
root.Interpret(context);
Console.WriteLine($"Matched words: {context.Output}");
}
}