Java 解释器模式详解
解释器模式(Interpreter Pattern)是一种行为型设计模式,用于定义语言的文法规则,并解释该语言中的句子。

核心概念
主要角色:
- 抽象表达式(AbstractExpression):定义解释操作的接口
- 终结符表达式(TerminalExpression):实现文法中的终结符操作
- 非终结符表达式(NonterminalExpression):实现文法中的非终结符操作
- 上下文(Context):包含解释器需要的全局信息
- 客户端(Client):构建抽象语法树并调用解释操作
经典案例:算术表达式解释器
实现一个简单的加减法表达式解释器,支持数字和 、 运算符。
步骤1:定义抽象表达式接口
// 抽象表达式接口
interface Expression {
int interpret(Context context);
}
步骤2:创建终结符表达式(数字)
// 终结符表达式 - 数字
class NumberExpression implements Expression {
private int number;
public NumberExpression(int number) {
this.number = number;
}
@Override
public int interpret(Context context) {
return number;
}
}
步骤3:创建非终结符表达式(运算符)
// 非终结符表达式 - 加法
class AddExpression implements Expression {
private Expression left; // 左操作数
private Expression right; // 右操作数
public AddExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Context context) {
return left.interpret(context) + right.interpret(context);
}
}
// 非终结符表达式 - 减法
class SubtractExpression implements Expression {
private Expression left;
private Expression right;
public SubtractExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Context context) {
return left.interpret(context) - right.interpret(context);
}
}
步骤4:创建上下文类
// 上下文类(此处可扩展存储变量值等)
class Context {
// 这里可以存储变量值映射等信息
// Map<String, Integer> variables;
// 此简单例子中不需要特殊内容
}
步骤5:创建解析器(可选,用于将表达式字符串转为语法树)
// 解析器 - 将表达式字符串解析为语法树
class Parser {
public static Expression parse(String expression) {
// 简单解析:支持 "数字 运算符 数字" 格式
String[] parts = expression.split(" ");
if (parts.length == 3) {
Expression left = new NumberExpression(Integer.parseInt(parts[0]));
Expression right = new NumberExpression(Integer.parseInt(parts[2]));
switch (parts[1]) {
case "+":
return new AddExpression(left, right);
case "-":
return new SubtractExpression(left, right);
default:
throw new IllegalArgumentException("不支持的运算符: " + parts[1]);
}
}
throw new IllegalArgumentException("无效表达式格式");
}
}
步骤6:客户端测试
public class InterpreterPatternDemo {
public static void main(String[] args) {
Context context = new Context();
// 方式一:手动构建语法树
System.out.println("=== 手动构建语法树 ===");
Expression add = new AddExpression(
new NumberExpression(10),
new NumberExpression(5)
);
System.out.println("10 + 5 = " + add.interpret(context));
Expression subtract = new SubtractExpression(
new NumberExpression(20),
new NumberExpression(8)
);
System.out.println("20 - 8 = " + subtract.interpret(context));
// 复杂表达式: (10 + 5) - (20 - 8)
Expression complex = new SubtractExpression(
new AddExpression(
new NumberExpression(10),
new NumberExpression(5)
),
new SubtractExpression(
new NumberExpression(20),
new NumberExpression(8)
)
);
System.out.println("(10 + 5) - (20 - 8) = " + complex.interpret(context));
// 方式二:使用解析器
System.out.println("\n=== 使用解析器 ===");
Expression parsedAdd = Parser.parse("15 + 7");
System.out.println("15 + 7 = " + parsedAdd.interpret(context));
Expression parsedSub = Parser.parse("100 - 33");
System.out.println("100 - 33 = " + parsedSub.interpret(context));
}
}
运行结果:
=== 手动构建语法树 ===
10 + 5 = 15
20 - 8 = 12
(10 + 5) - (20 - 8) = 3
=== 使用解析器 ===
15 + 7 = 22
100 - 33 = 67
进阶案例:布尔表达式解释器
实现支持 AND、OR、NOT 的布尔表达式解释器。
// 上下文类
class BooleanContext {
private Map<String, Boolean> variables = new HashMap<>();
public void setVariable(String name, boolean value) {
variables.put(name, value);
}
public boolean getVariable(String name) {
return variables.getOrDefault(name, false);
}
}
// 抽象表达式
interface BooleanExpression {
boolean interpret(BooleanContext context);
}
// 变量表达式(终结符)
class VariableExpression implements BooleanExpression {
private String name;
public VariableExpression(String name) {
this.name = name;
}
@Override
public boolean interpret(BooleanContext context) {
return context.getVariable(name);
}
}
// 常量表达式(终结符)
class ConstantExpression implements BooleanExpression {
private boolean value;
public ConstantExpression(boolean value) {
this.value = value;
}
@Override
public boolean interpret(BooleanContext context) {
return value;
}
}
// AND 表达式(非终结符)
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 interpret(BooleanContext context) {
return left.interpret(context) && right.interpret(context);
}
}
// OR 表达式(非终结符)
class OrExpression implements BooleanExpression {
private BooleanExpression left;
private BooleanExpression right;
public OrExpression(BooleanExpression left, BooleanExpression right) {
this.left = left;
this.right = right;
}
@Override
public boolean interpret(BooleanContext context) {
return left.interpret(context) || right.interpret(context);
}
}
// NOT 表达式(非终结符)
class NotExpression implements BooleanExpression {
private BooleanExpression expression;
public NotExpression(BooleanExpression expression) {
this.expression = expression;
}
@Override
public boolean interpret(BooleanContext context) {
return !expression.interpret(context);
}
}
// 测试
public class BooleanInterpreterDemo {
public static void main(String[] args) {
BooleanContext context = new BooleanContext();
context.setVariable("A", true);
context.setVariable("B", false);
context.setVariable("C", true);
// (A AND B) OR (NOT B AND C)
BooleanExpression expr = new OrExpression(
new AndExpression(
new VariableExpression("A"),
new VariableExpression("B")
),
new AndExpression(
new NotExpression(new VariableExpression("B")),
new VariableExpression("C")
)
);
System.out.println("(A AND B) OR (NOT B AND C) where A=true, B=false, C=true");
System.out.println("Result: " + expr.interpret(context)); // true
}
}
实际应用场景
-
SQL 解析器
将 SQL 语句解析为语法树执行
-
正则表达式引擎
解释正则表达式模式匹配
-
数学表达式计算器
如公式引擎、科学计算器
-
配置文件解析
如 Spring 的 SpEL 表达式
-
脚本语言解释器
小型 DSL(领域特定语言)的实现
优缺点分析
优点:
- 易于扩展文法(添加新表达式类)
- 实现了文法分离,易于维护
- 可以方便地实现复杂表达式
缺点:
- 对于复杂文法,类层次会变得庞大
- 执行效率较低(递归调用)
- 不适合处理非常复杂的语言
最佳实践建议
- 使用时机:当需要解释简单语言且语法规则稳定时考虑使用
- 组合使用:常与组合模式一起使用构建语法树
- 性能优化:可以使用缓存或 Flyweight 模式优化
- 简化实现:对于简单场景,可以考虑使用脚本引擎(如 ScriptEngine)替代
解释器模式虽然不常用,但在需要自定义 DSL 或解析特定格式数据时非常有用,理解其原理有助于设计更灵活的架构。