一、理论
解释器模式(Interpreter Pattern)是一种按照规定语法进行解析的方案,在现在项目中使用较少,其定义如下:
Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
-
AbstractExpression——抽象解释器
AbstractExpression角色定义了语法树节点的共同接口(API)
-
TerminalExpression——终结符表达式
实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符。
-
NonterminalExpression——非终结符表达式
文法中的每条规则对应于一个非终结表达式,非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。
-
Context——环境角色
含有解释器之外的全局信息
在编译原理中,一个算术表达式通过词法分析器形成词法单元,而后这些词法单元再通过语法分析器构建语法分析树,最终形成一颗抽象的语法分析树。这里的词法分析器和语法分析器都可以看做是解释器。
二、代码
模拟一个加减计算器:
AbstractExpression——抽象解释器
public abstract class Expression {
public abstract int interpreter(HashMap<String, Integer> var);
}
TerminalExpression——终结符表达式
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);
}
}
NonterminalExpression——非终结符表达式
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 AddSymbolExpression extends SymbolExpression {
public AddSymbolExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpreter(HashMap<String, Integer> var) {
return super.left.interpreter(var) + super.right.interpreter(var);
}
}
public class MinusSymbolExpression extends SymbolExpression {
public MinusSymbolExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public int interpreter(HashMap<String, Integer> var) {
return left.interpreter(var) - right.interpreter(var);
}
}
计算器和测试类:
public class Calculator {
private Expression expression;
public Calculator(String expStr) {
Stack<Expression> stack = new Stack<>();
char[] charArray = expStr.toCharArray();
Expression left = null;
Expression right = null;
for (int i = 0; i < charArray.length; i++) {
switch (charArray[i]) {
case '+':
left = stack.pop();
right = new VarExpression(String.valueOf(charArray[++i]));
stack.push(new AddSymbolExpression(left, right));
break;
case '-':
left = stack.pop();
right = new VarExpression(String.valueOf(charArray[++i]));
stack.push(new MinusSymbolExpression(left, right));
break;
default:
stack.push(new VarExpression(String.valueOf(charArray[i])));
break;
}
}
this.expression = stack.pop();
}
public int run(HashMap<String, Integer> var) {
return this.expression.interpreter(var);
}
}
public class Client {
public static void main(String[] args) throws IOException {
String expStr = getExpStr();
HashMap<String, Integer> map = getValue(expStr);
Calculator calculator = new Calculator(expStr);
System.out.println("计算机构:" + expStr + "=" + calculator.run(map));
}
public static String getExpStr() throws IOException {
System.out.println("请输入表达式");
return new BufferedReader(new InputStreamReader(System.in)).readLine();
}
//Context角色
public static HashMap<String, Integer> getValue(String expStr) throws IOException {
HashMap hashMap = new HashMap();
for (char c : expStr.toCharArray()) {
if (c != '+' && c != '-') {
if (!hashMap.containsKey(String.valueOf(c))) {
System.out.println("请输入" + String.valueOf(c) + "的值:");
String in = new BufferedReader(new InputStreamReader(System.in)).readLine();
hashMap.put(String.valueOf(c), Integer.valueOf(in));
}
}
}
return hashMap;
}
}
三、总结
- 当有一个语言需要解释执行,可将该语言中的句子表示为一个抽象语法树,就可以考虑使用解释器模式,让程序具有良好的扩展性
- 应用场景:编译器、运算表达式计算、正则表达式、机器人等
- 使用解释器可能带来的问题:解释器模式会引起类膨胀、解释器模式采用递归调用方法,将会导致调试非常复杂、效率可能降低.