设计模式(20)——解释器模式

本文介绍解释器模式的概念和应用。

基本思想和原则

给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

动机

当有一些简单的语法需要解析时,可以考虑使用解释器模式建立规则,比如解析各种格式的日志。

实现

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
public abstract class Expression {
public abstract int interpreter(HashMap<String, Integer> var);
}

public class VarExpression extends Expression {
private String key;

public VarExpression(String key) {
this.key = key;
}

@Override
public int interpreter(HashMap<String, Integer> var) {
return var.get(this.key);
}
}

public abstract class SymbolExpression extends Expression {
protected Expression left;
protected Expression right;

public SymbolExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
}

public class AddExpression extends SymbolExpression {
public AddExpression(Expression left, Expression right) {
super(left, right);
}

public int interpreter(HashMap<String, Integer> var) {
return this.left.interpreter(var) + this.right.interpreter(var);
}
}

public class SubExpression extends SymbolExpression{
public SubExpression(Expression left, Expression right) {
super(left, right);
}

public int interpreter(HashMap<String, Integer> var) {
return this.left.interpreter(var) - this.right.interpreter(var);
}
}

public class Calculator {
private Expression expression;
private Stack<Expression> stack = new Stack<Expression>();

public Calculator(String expStr) {
char[] charArray = expStr.toCharArray();

Expression left = null;
Expression right = null;

for (int i = 0; i < charArray.length; i++) {
switch (charArray[i]) {
case '+':
left = this.stack.pop();
right = new VarExpression(String.valueOf(charArray[++i]));
this.stack.push(new AddExpression(left, right));
break;
case '-':
left = this.stack.pop();
right = new VarExpression(String.valueOf(charArray[++i]));
this.stack.push(new SubExpression(left, right));
break;
default:
this.stack.push(new VarExpression(String.valueOf(charArray[i])));
}
}
this.expression = this.stack.pop();
}

public int run(HashMap<String, Integer> var) {
return this.expression.interpreter(var);
}
}

public class Test {
public static void main(String[] args) {
String expStr1 = "a+b-c";
HashMap<String, Integer> var1 = new HashMap<String, Integer>();
var1.put("a", 10);
var1.put("b", 2);
var1.put("c", 5);
Calculator calculator1 = new Calculator(expStr1);
int res1 = calculator1.run(var1);
System.out.println(expStr1 + "=" + res1);

String expStr2 = "a+b-c-d";
HashMap<String, Integer> var2 = new HashMap<String, Integer>();
var2.put("a", 100);
var2.put("b", 34);
var2.put("c", 12);
var2.put("d", 8);
Calculator calculator2 = new Calculator(expStr1);
int res2 = calculator2.run(var2);
System.out.println(expStr1 + "=" + res2);
}
}

输出如下:

1
2
a+b-c=7
a+b-c-d=122

优点

解释器模式的优点是扩展性比较好,当需要增加语法规则时,只需要增加独立的类并实现即可。

缺点

当语法规则复杂时,类数量膨胀非常厉害,解释器模式使用递归的方式来处理问题,会一定程度上影响性能。