👉文章示例代码👈
定义
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
定义中提到的文法和句子的概念同编译原理中的描述相同,“文法”指的语言的语法规则,而“句子”是指语言集中的元素。
四个角色
解释器模式主要有四个角色:
- 环境角色Context:包含解释器之外的一些全局信息。
- 抽象表达式AbstractExpression:声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。
- 终结符表达式TerminalExpression:实现与文法中的终结符相关联的解释操作。
- 非终结符表达式NonterminalExpression:为文法中的非终结符实现解释操作,对文法中每一条规则R1、R2…Rn都需要一个具体的非终结符表达式类。
场景示例
笔者这里通过解释器模式来实现运算表达式的计算,例如计算表达式A-B+C的值。
创建抽象表达式
1 2 3 4 5 6 7 8 9 10 11 12
|
public interface Expression {
int interpret(); }
|
创建终结符表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
|
public class AddExpression implements Expression {
private Expression left;
private Expression right;
public AddExpression(Expression left, Expression right) { this.left = left; this.right = right; }
public int interpret() { return this.left.interpret() + this.right.interpret(); } }
public class SubExpression implements Expression {
private Expression left;
private Expression right;
public SubExpression(Expression left, Expression right) { this.left = left; this.right = right; }
public int interpret() { return this.left.interpret() - this.right.interpret(); } }
|
创建非终结符表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
public class NumberExpression implements Expression {
private int number;
public NumberExpression(int number) { this.number = number; }
public NumberExpression(String number) { this.number = Integer.valueOf(number); }
public int interpret() { return this.number; }
@Override public String toString() { return String.format("%s", this.number); } }
|
创建环境角色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
|
public class ExpressionContext {
private Expression expression;
public int parse(String expStr) { final Stack<Expression> stack = new Stack<Expression>();
String[] expArray = expStr.split(",");
Expression left; Expression right;
for (int i = 0; i < expArray.length; i++) { String exp = expArray[i]; if (isSymbol(exp)) { left = stack.pop(); right = new NumberExpression(expArray[++i]); System.out.println(String.format("数字%s和%s开始进行%s操作运算", left, right, exp)); Expression expression = getExpression(left, right, exp);
int result = expression.interpret(); System.out.println(String.format("运算结果%s开始入栈", result)); stack.push(new NumberExpression(result)); } else { NumberExpression numberExpression = new NumberExpression(exp); System.out.println(String.format("数字%s开始入栈", numberExpression)); stack.push(numberExpression); } }
return stack.pop().interpret(); }
private boolean isSymbol(String exp) { return "+".equals(exp) || "-".equals(exp); }
private Expression getExpression(Expression left, Expression right, String symbol) { if ("+".equals(symbol)) { return new AddExpression(left, right); } else if ("-".equals(symbol)) { return new SubExpression(left, right); } else { throw new RuntimeException(String.format("当前解析器不支持该操作符%s的解析", symbol)); } } }
|
测试类及输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
public class Test {
public static void main(String[] args) { String expStr = "10,-,4,+,1"; ExpressionContext expressionContext = new ExpressionContext(); int parse = expressionContext.parse(expStr); System.out.println("表达式最终的运算结果为: " + parse); } }
|
输出结果如下:
数字10开始入栈
数字10和4开始进行-操作运算
运算结果6开始入栈
数字6和1开始进行+操作运算
运算结果7开始入栈
表达式最终的运算结果为: 7
类结构图
以上示例类的结构图如下所示

总结
解释器模式在实际的软件开发中使用比较少,因为它会引起效率、性能以及维护等问题。
适用场景
- 将一个需要解释执行的语言中的句子表示为一个抽象语法树。
- 某种类型的问题重复出现可以用一种简单的语言来进行表达。
- 简单语法需要解释的场景。
优点
缺点
- 当语法规则数目太多时,类的个数将急剧增加,导致系统的复杂度增加。
- 解释器模式采用大量的循环和递归调用,执行效率较为低下。
参考