Appearance
解释器模式(Interpreter Pattern)
定义
解释器模式是一种行为设计模式,它定义了一个语言的文法,并且建立一个解释器来解释该语言中的句子。
英文原文定义:
The Interpreter Pattern defines a grammatical representation for a language and an interpreter to interpret the grammar.
核心概念
解释器模式通过构建语法树和定义节点类来实现语言的解释执行,主要应用于特定类型问题的频繁解释场景。
主要角色
- AbstractExpression(抽象表达式):声明抽象解释操作
- TerminalExpression(终结符表达式):实现与文法中终结符相关的解释操作
- NonterminalExpression(非终结符表达式):实现文法规则的解释操作
- Context(上下文):包含解释器之外的全局信息
- Client(客户端):构建语法树并调用解释操作
优缺点
优点
- 易于扩展文法:新增表达式类即可扩展语言
- 实现文法简单:每个语法规则对应一个类
- 适合领域语言:特别适合特定领域简单语言实现
- 灵活组合:通过对象组合可方便地改变/扩展文法
缺点
- 复杂文法难维护:文法规则很多时,类层次结构会变得庞大
- 执行效率较低:解释型执行通常比编译型慢
- 应用场景有限:仅适用于文法简单的语言
- 类膨胀问题:每个规则都需要对应的类
解决的问题
解释器模式主要解决以下经典问题:
- 领域特定语言:需要实现简单领域特定语言(DSL)时
- 语法分析:当有一个语言需要解释执行时
- 频繁变化文法:文法可能频繁变化的场景
- 表达式求值:数学表达式、布尔表达式等解释执行
- 规则引擎:简单规则引擎的实现
实现注意事项
文法复杂度控制:
- 适合文法简单的场景
- 复杂文法考虑使用解析器生成工具
抽象语法树构建:
- 客户端负责构建语法树
- 可结合组合模式构建树结构
共享终结符:
- 终结符可以共享实例
- 使用享元模式优化
解释方向:
- 递归下降解释
- 迭代解释
错误处理:
- 设计良好的错误报告机制
- 考虑失败安全解释
实现变体
基于组合模式:
- 使用组合模式构建表达式树
- 统一处理叶节点和组合节点
基于访问者模式:
- 使用访问者分离文法与操作
- 便于新增操作而不修改表达式类
基于扩展方法:
- 在支持扩展方法的语言中
- 为表达式基类添加解释方法
动态解释器:
- 使用反射等动态技术
- 运行时构建解释逻辑
与其他模式的关系
相似模式区分
组合模式:
- 解释器:通常用组合模式构建语法树
- 组合:描述部分-整体层次结构
访问者模式:
- 解释器:可结合访问者分离文法与操作
- 访问者:封装对复杂结构的操作
策略模式:
- 解释器:封装解释算法
- 策略:封装可互换的算法
常见搭配组合
- 解释器 + 组合:构建抽象语法树
- 解释器 + 享元:共享终结符实例
- 解释器 + 访问者:实现多种解释操作
- 解释器 + 建造者:逐步构建复杂语法树
典型应用场景
- 正则表达式引擎
- SQL语法解析
- 数学公式计算器
- 业务规则引擎
- 配置文件解析
- 简单编程语言实现
- 模板引擎
代码示例(布尔表达式解释器)
java
// 抽象表达式
interface BooleanExpression {
boolean evaluate(Context context);
BooleanExpression replace(String var, BooleanExpression exp);
BooleanExpression copy();
}
// 终结符表达式:变量
class VariableExpression implements BooleanExpression {
private String name;
public VariableExpression(String name) {
this.name = name;
}
@Override
public boolean evaluate(Context context) {
return context.lookup(name);
}
@Override
public BooleanExpression replace(String var, BooleanExpression exp) {
return name.equals(var) ? exp.copy() : new VariableExpression(name);
}
@Override
public BooleanExpression copy() {
return new VariableExpression(name);
}
}
// 非终结符表达式:与操作
class AndExpression implements BooleanExpression {
private BooleanExpression left;
private BooleanExpression right;
public AndExpression(BooleanExpression left, BooleanExpression right) {
this.left = left;
this.right = right;
}
@Override
public boolean evaluate(Context context) {
return left.evaluate(context) && right.evaluate(context);
}
@Override
public BooleanExpression replace(String var, BooleanExpression exp) {
return new AndExpression(
left.replace(var, exp),
right.replace(var, exp)
);
}
@Override
public BooleanExpression copy() {
return new AndExpression(left.copy(), right.copy());
}
}
// 上下文
class Context {
private Map<String, Boolean> variables = new HashMap<>();
public void assign(String var, boolean value) {
variables.put(var, value);
}
public boolean lookup(String var) {
Boolean value = variables.get(var);
if (value == null) {
throw new IllegalArgumentException();
}
return value;
}
}
// 客户端代码
public class BooleanInterpreter {
public static void main(String[] args) {
// 构建表达式:(x AND y)
BooleanExpression x = new VariableExpression("x");
BooleanExpression y = new VariableExpression("y");
BooleanExpression exp = new AndExpression(x, y);
Context context = new Context();
context.assign("x", true);
context.assign("y", false);
boolean result = exp.evaluate(context);
System.out.println("(x AND y) = " + result); // 输出 false
}
}