解释器模式大白话讲解
一句话概括
就像翻译官:你把一种语言(表达式)交给它,它帮你翻译成你能理解的意思(结果)
现实生活比喻
场景1:计算器
- 你 :输入
"1 + 2 * 3" - 解释器 :分析这个字符串,理解
*比+优先级高,先算2*3=6,再算1+6=7 - 结果 :
7
场景2:SQL查询
- 你 :输入
"SELECT * FROM users WHERE age > 18" - 解释器 :分析语法,找出
users表中所有age大于18的记录 - 结果:符合条件的数据列表
完整代码示例
场景1:四则运算计算器
java
/**
* 解释器模式 - 四则运算计算器
*/
public class Main {
public static void main(String[] args) {
System.out.println("=== 四则运算计算器 ===");
// 测试简单表达式
String expression1 = "3 + 5";
String expression2 = "10 - 4";
String expression3 = "6 * 2";
String expression4 = "15 / 3";
Calculator calculator = new Calculator();
System.out.println(expression1 + " = " + calculator.calculate(expression1));
System.out.println(expression2 + " = " + calculator.calculate(expression2));
System.out.println(expression3 + " = " + calculator.calculate(expression3));
System.out.println(expression4 + " = " + calculator.calculate(expression4));
// 测试复杂表达式
System.out.println("\n=== 复杂表达式测试 ===");
String expression5 = "3 + 5 * 2 - 8 / 4";
System.out.println(expression5 + " = " + calculator.calculate(expression5));
// 测试带括号的表达式
System.out.println("\n=== 带括号表达式测试 ===");
String expression6 = "(3 + 5) * 2";
System.out.println(expression6 + " = " + calculator.calculate(expression6));
String expression7 = "3 * (5 + 2) - 4";
System.out.println(expression7 + " = " + calculator.calculate(expression7));
// 测试错误表达式
System.out.println("\n=== 错误表达式测试 ===");
String errorExpression = "3 + * 5";
try {
System.out.println(errorExpression + " = " + calculator.calculate(errorExpression));
} catch (IllegalArgumentException e) {
System.out.println("表达式错误: " + e.getMessage());
}
}
}
/**
* 抽象表达式接口
*/
interface Expression {
int interpret();
}
/**
* 终结符表达式 - 数字
*/
class NumberExpression implements Expression {
private int number;
public NumberExpression(int number) {
this.number = number;
}
@Override
public int interpret() {
return number;
}
}
/**
* 非终结符表达式 - 加法
*/
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() {
return left.interpret() + right.interpret();
}
}
/**
* 非终结符表达式 - 减法
*/
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() {
return left.interpret() - right.interpret();
}
}
/**
* 非终结符表达式 - 乘法
*/
class MultiplyExpression implements Expression {
private Expression left;
private Expression right;
public MultiplyExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
return left.interpret() * right.interpret();
}
}
/**
* 非终结符表达式 - 除法
*/
class DivideExpression implements Expression {
private Expression left;
private Expression right;
public DivideExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
int divisor = right.interpret();
if (divisor == 0) {
throw new ArithmeticException("除数不能为0");
}
return left.interpret() / divisor;
}
}
/**
* 计算器 - 上下文
*/
class Calculator {
/**
* 解析并计算表达式
*/
public int calculate(String expression) {
// 移除空格
expression = expression.replaceAll("\\s+", "");
// 使用栈来处理表达式
Stack<Expression> numberStack = new Stack<>();
Stack<Character> operatorStack = new Stack<>();
for (int i = 0; i < expression.length(); i++) {
char ch = expression.charAt(i);
if (Character.isDigit(ch)) {
// 处理多位数字
int num = 0;
while (i < expression.length() && Character.isDigit(expression.charAt(i))) {
num = num * 10 + (expression.charAt(i) - '0');
i++;
}
i--; // 回退一位
numberStack.push(new NumberExpression(num));
} else if (ch == '(') {
operatorStack.push(ch);
} else if (ch == ')') {
// 处理括号内的所有运算
while (!operatorStack.isEmpty() && operatorStack.peek() != '(') {
processOperation(numberStack, operatorStack);
}
operatorStack.pop(); // 弹出 '('
} else if (isOperator(ch)) {
// 处理运算符优先级
while (!operatorStack.isEmpty() && precedence(operatorStack.peek()) >= precedence(ch)) {
processOperation(numberStack, operatorStack);
}
operatorStack.push(ch);
} else {
throw new IllegalArgumentException("非法字符: " + ch);
}
}
// 处理剩余的运算符
while (!operatorStack.isEmpty()) {
processOperation(numberStack, operatorStack);
}
return numberStack.pop().interpret();
}
/**
* 处理一次运算
*/
private void processOperation(Stack<Expression> numberStack, Stack<Character> operatorStack) {
char operator = operatorStack.pop();
Expression right = numberStack.pop();
Expression left = numberStack.pop();
switch (operator) {
case '+':
numberStack.push(new AddExpression(left, right));
break;
case '-':
numberStack.push(new SubtractExpression(left, right));
break;
case '*':
numberStack.push(new MultiplyExpression(left, right));
break;
case '/':
numberStack.push(new DivideExpression(left, right));
break;
}
}
/**
* 判断是否是运算符
*/
private boolean isOperator(char ch) {
return ch == '+' || ch == '-' || ch == '*' || ch == '/';
}
/**
* 获取运算符优先级
*/
private int precedence(char operator) {
switch (operator) {
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
default:
return 0;
}
}
}
运行结果
=== 四则运算计算器 ===
3 + 5 = 8
10 - 4 = 6
6 * 2 = 12
15 / 3 = 5
=== 复杂表达式测试 ===
3 + 5 * 2 - 8 / 4 = 11
=== 带括号表达式测试 ===
(3 + 5) * 2 = 16
3 * (5 + 2) - 4 = 17
=== 错误表达式测试 ===
表达式错误: 非法字符: *

场景2:布尔表达式解析器
java
/**
* 解释器模式 - 布尔表达式解析器
*/
public class BooleanExpressionExample {
public static void main(String[] args) {
System.out.println("=== 布尔表达式解析器 ===");
// 创建上下文(变量值)
Context context = new Context();
context.setVariable("A", true);
context.setVariable("B", false);
context.setVariable("C", true);
context.setVariable("D", false);
// 解析表达式
System.out.println("\n--- 测试简单表达式 ---");
testExpression("A AND B", context); // true AND false = false
testExpression("A OR B", context); // true OR false = true
testExpression("NOT A", context); // NOT true = false
System.out.println("\n--- 测试复杂表达式 ---");
testExpression("A AND B OR C", context); // true AND false OR true = true
testExpression("(A OR B) AND C", context); // (true OR false) AND true = true
testExpression("NOT (A AND B)", context); // NOT (true AND false) = true
System.out.println("\n--- 测试不同变量值 ---");
context.setVariable("A", false);
context.setVariable("B", true);
testExpression("A AND B", context); // false AND true = false
testExpression("A OR B", context); // false OR true = true
}
private static void testExpression(String expression, Context context) {
try {
BooleanExpression boolExpr = new BooleanExpressionParser(expression).parse();
boolean result = boolExpr.interpret(context);
System.out.println(expression + " = " + result);
} catch (Exception e) {
System.out.println("解析错误: " + e.getMessage());
}
}
}
/**
* 上下文 - 存储变量值
*/
class Context {
private Map<String, Boolean> variables = new HashMap<>();
public void setVariable(String name, boolean value) {
variables.put(name, value);
}
public boolean getVariable(String name) {
Boolean value = variables.get(name);
if (value == null) {
throw new IllegalArgumentException("变量未定义: " + name);
}
return value;
}
}
/**
* 抽象布尔表达式接口
*/
interface BooleanExpression {
boolean interpret(Context context);
}
/**
* 终结符表达式 - 变量
*/
class VariableExpression implements BooleanExpression {
private String name;
public VariableExpression(String name) {
this.name = name;
}
@Override
public boolean interpret(Context context) {
return context.getVariable(name);
}
}
/**
* 终结符表达式 - 常量
*/
class ConstantExpression implements BooleanExpression {
private boolean value;
public ConstantExpression(boolean value) {
this.value = value;
}
@Override
public boolean interpret(Context 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(Context 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(Context 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(Context context) {
return !expression.interpret(context);
}
}
/**
* 布尔表达式解析器
*/
class BooleanExpressionParser {
private String expression;
private int pos = 0;
public BooleanExpressionParser(String expression) {
this.expression = expression.replaceAll("\\s+", "");
}
public BooleanExpression parse() {
return parseOrExpression();
}
// 解析OR表达式: A OR B OR C
private BooleanExpression parseOrExpression() {
BooleanExpression left = parseAndExpression();
while (pos < expression.length() && peek().equals("OR")) {
consume("OR");
BooleanExpression right = parseAndExpression();
left = new OrExpression(left, right);
}
return left;
}
// 解析AND表达式: A AND B AND C
private BooleanExpression parseAndExpression() {
BooleanExpression left = parseNotExpression();
while (pos < expression.length() && peek().equals("AND")) {
consume("AND");
BooleanExpression right = parseNotExpression();
left = new AndExpression(left, right);
}
return left;
}
// 解析NOT表达式: NOT A
private BooleanExpression parseNotExpression() {
if (peek().equals("NOT")) {
consume("NOT");
return new NotExpression(parseNotExpression());
}
return parsePrimary();
}
// 解析基本表达式: 变量、常量或括号表达式
private BooleanExpression parsePrimary() {
String token = peek();
if (token.equals("(")) {
consume("(");
BooleanExpression expr = parseOrExpression();
consume(")");
return expr;
} else if (token.equals("TRUE")) {
consume("TRUE");
return new ConstantExpression(true);
} else if (token.equals("FALSE")) {
consume("FALSE");
return new ConstantExpression(false);
} else {
// 变量
if (!isValidVariable(token)) {
throw new IllegalArgumentException("非法变量名: " + token);
}
consume(token);
return new VariableExpression(token);
}
}
// 查看下一个token
private String peek() {
if (pos >= expression.length()) {
return "";
}
// 如果是运算符或括号
if (expression.charAt(pos) == '(' || expression.charAt(pos) == ')') {
return String.valueOf(expression.charAt(pos));
}
// 提取单词
int start = pos;
while (pos < expression.length() && Character.isLetter(expression.charAt(pos))) {
pos++;
}
String word = expression.substring(start, pos);
pos = start; // 重置位置
// 检查是否是关键字
if (word.equalsIgnoreCase("AND") || word.equalsIgnoreCase("OR") ||
word.equalsIgnoreCase("NOT") || word.equalsIgnoreCase("TRUE") ||
word.equalsIgnoreCase("FALSE")) {
return word.toUpperCase();
}
return word;
}
// 消费一个token
private void consume(String expected) {
String token = peek();
if (!token.equals(expected)) {
throw new IllegalArgumentException("期望: " + expected + ", 实际: " + token);
}
if (token.length() == 1 && (token.equals("(") || token.equals(")"))) {
pos++; // 括号
} else {
pos += token.length(); // 单词
}
}
// 检查是否是有效的变量名
private boolean isValidVariable(String token) {
return token.matches("[A-Za-z][A-Za-z0-9_]*");
}
}
运行结果
=== 布尔表达式解析器 ===
--- 测试简单表达式 ---
A AND B = false
A OR B = true
NOT A = false
--- 测试复杂表达式 ---
A AND B OR C = true
(A OR B) AND C = true
NOT (A AND B) = true
--- 测试不同变量值 ---
A AND B = false
A OR B = true
解释器模式的核心结构
Client(客户端)
↓ 输入表达式
Context(上下文)
↓
AbstractExpression(抽象表达式)
↑ 实现
TerminalExpression(终结符表达式)
NonterminalExpression(非终结符表达式)
关键概念:
- 抽象语法树(AST):表达式解析后的树形结构
- 终结符:不能再分解的基本元素(数字、变量)
- 非终结符:由其他表达式组成的复合元素(运算符、函数)
- 上下文:存储解释器需要的外部信息
解释器模式的工作流程
输入表达式 → 词法分析 → 语法分析 → 构建AST → 解释执行 → 输出结果
↓ ↓ ↓ ↓ ↓ ↓
"1+2*3" → ["1","+","2","*","3"] → 语法树 → 遍历计算 → 7
适用场景(大白话版)
✅ 适合用解释器模式的场景:
-
简单语言解释器
java// 正则表达式、SQL查询、四则运算 // 需要定义简单语法规则的系统 -
配置文件解析
java// Spring的SpEL表达式、日志配置表达式 // 需要动态解析配置的系统 -
业务规则引擎
java// 风控规则、促销规则、审批规则 // 规则经常变化,需要灵活配置 -
模板引擎
java// JSP、Thymeleaf、Freemarker // 需要解释模板语法的系统
❌ 不适合的场景:
- 复杂语法:如果语法非常复杂,解释器模式会变得很臃肿
- 性能要求高:解释执行通常比编译执行慢
- 语法经常变化:每次语法变化都需要修改解释器
- 已经有现成解析器:如JSON、XML解析有成熟库
优缺点
优点:
- 易于扩展语法:新增语法规则只需新增表达式类
- 易于实现:每个语法规则对应一个类,结构清晰
- 灵活性高:可以动态改变解释逻辑
缺点:
- 复杂语法难维护:语法复杂时,类数量会爆炸
- 效率较低:解释执行比直接执行慢
- 难以调试:解释器错误难以定位
实际应用案例
1. Java正则表达式
java
// Pattern就是解释器模式的实现
Pattern pattern = Pattern.compile("a*b");
Matcher matcher = pattern.matcher("aaaaab");
boolean matches = matcher.matches(); // true
2. Spring表达式语言(SpEL)
java
// SpEL使用解释器模式解析表达式
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello ' + name");
String message = exp.getValue(context, String.class);
3. SQL解析器
java
// 数据库查询优化器使用解释器模式
// 解析SQL语句,生成执行计划
SELECT * FROM users WHERE age > 18 AND status = 'ACTIVE'
4. 规则引擎(Drools)
java
// 规则引擎使用解释器模式解析业务规则
rule "成年人规则"
when
$p : Person(age > 18)
then
$p.setAdult(true);
end
与编译器的区别
| 方面 | 解释器模式 | 编译器 |
|---|---|---|
| 执行方式 | 边解析边执行 | 先编译后执行 |
| 速度 | 较慢 | 较快 |
| 灵活性 | 高,可动态修改 | 低,需要重新编译 |
| 典型应用 | 脚本语言、配置文件 | 系统编程语言 |
总结
解释器模式就是:
- 语言翻译官:把一种语言翻译成另一种语言
- 规则执行者:按照预定义规则执行操作
- 公式计算器:解析并计算公式
核心口诀:
特定语言要解析,
解释模式来解决。
语法规则拆细碎,
逐条解释出结果!
就像现实中的:
- 📖 翻译软件:把英文翻译成中文
- 🧮 计算器:把数学表达式算出结果
- 🗺️ 地图应用:把地址解析成坐标
- 📧 邮件过滤器:把过滤规则应用到邮件
记住:当需要解释特定语法或规则,且语法相对简单固定时,考虑使用解释器模式!对于复杂语法,考虑使用专门的解析器生成工具(如ANTLR、Yacc等)。