解释器模式

定义

给定一个语言,定义它的文法大的一种表示,并定义一个解释器,这个解释器使用该表示类解释语言中的句子。
为了解释一种语言,而为语言创建的解释器。
类型:行为型

适用场景

  • 某个特定类型问题发生频率足够高

优点和缺点

优点

  • 扩展性好。由于在解释器模式中适用类来表示语言的文法规则,因此可以通过继承等机制类改变或者扩展文法。
  • 容易实现。在语法树中的每个表达式节点都是类似的,所以实现其文法较为容易。

缺点

  • 执行效率较低。解释器模式中通常适用大量的循环和递归调用,担当要解释大的句子较复杂时,其运行速度很慢,且代码的调试过程也比较麻烦。
  • 会引起类膨胀。解释器模式中的每条规则至少定义一个类,担当包含的文法规则很多时,类的个数将急剧增加,导致系统难以管理和维护。
  • 可应用大的场景比较少。在软件开发中,需要定义语言文法大的应用实力非常少,所以这种模式很少被适用到。

模式结构

  • 抽象表达式角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法interpret()
  • 终结符表达式角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
  • 非终结符表示式角色:也是抽象表达式的子类,用来表现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符 表达式。
  • 环境角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
  • 客户端:主要任务是将需要分析的句子表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。

代码实现

比如我们创建一个对6 100 11 + *这个式子的解释器,解释规则是如果是数字就入栈,如果是符号就将入栈的后两个数字(先进后出)进行计算
抽象表达式类

1
2
3
public interface Interpreter {
int interpret();
}

非终结符号表达式类
加法解释器类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class AddInterpreter implements Interpreter {

private Interpreter firstExpression, secondExpression;

public AddInterpreter(Interpreter firstExpression, Interpreter secondExpression) {
this.firstExpression = firstExpression;
this.secondExpression = secondExpression;
}

@Override
public int interpret() {
return this.firstExpression.interpret() + this.secondExpression.interpret();
}

@Override
public String toString() {
return "+";
}
}

非终结符号表达式类
乘法解释器类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MultiInterpreter implements Interpreter {

private Interpreter firstExpression, secondExpression;

public MultiInterpreter(Interpreter firstExpression, Interpreter secondExpression) {
this.firstExpression = firstExpression;
this.secondExpression = secondExpression;
}

@Override
public int interpret() {
return this.firstExpression.interpret() * this.secondExpression.interpret();
}

@Override
public String toString() {
return "*";
}
}

终结符号表达式类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class NumberInterpreter implements Interpreter{

private int number;

public NumberInterpreter(int number) {
this.number = number;
}

public NumberInterpreter(String number) {
this.number = Integer.parseInt(number);
}

@Override
public int interpret() {
return 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
public class ExpressionParser {

private Stack<Interpreter> stack = new Stack<>();

public int parse(String str) {
String[] strItemArray = str.split(" ");
for (String symbol : strItemArray) {
if (!isOperator(symbol)) {
Interpreter numberInterpreter = new NumberInterpreter(symbol);
stack.push(numberInterpreter);
System.out.printf("入栈:%d%n", numberInterpreter.interpret());
} else {
Interpreter firstExpression = stack.pop();
Interpreter secondExpression = stack.pop();
System.out.printf("出栈:%d 和 %d%n", firstExpression.interpret(), secondExpression.interpret());
Interpreter expressionObject = getExpressionObject(firstExpression, secondExpression, symbol);
System.out.printf("应用运算符:%s%n", expressionObject.toString());
int result = expressionObject.interpret();
NumberInterpreter resultExpression = new NumberInterpreter(result);
stack.push(resultExpression);
System.out.println(String.format("阶段结果入栈: %d",resultExpression.interpret()));
}
}
int result = stack.pop().interpret();
return result;
}

public boolean isOperator(String symbol) {
return (symbol.equals("+") || symbol.equals("*"));
}

public Interpreter getExpressionObject(Interpreter firstExpression, Interpreter secondExpression, String symbol) {
if (symbol.equals("+")) {
return new AddInterpreter(firstExpression, secondExpression);
} else if (symbol.equals("*")) {
return new MultiInterpreter(firstExpression, secondExpression);
}
return null;
}

}

客户端

1
2
3
4
5
6
7
8
9
public class Test {
public static void main(String[] args) {
String inputStr = "6 100 11 + *";
ExpressionParser expressionParser = new ExpressionParser();
int result = expressionParser.parse(inputStr);
System.out.println("解释器计算结果:" + result);

}
}

结果:

1
2
3
4
5
6
7
8
9
10
入栈:6
入栈:100
入栈:11
出栈:11 和 100
应用运算符:+
阶段结果入栈: 111
出栈:111 和 6
应用运算符:*
阶段结果入栈: 666
解释器计算结果:666

UML类图