创建数字表达式类:
public class NumInterpreter implements IArithmeticInterpreter { private int value; public NumInterpreter(int value) { this.value = value; } public int interpret() { return this.value; } }
创建计算器类:不在乎乘除与加减得顺序,这都是解释器按照语义得解释,本案例中按照顺序执行
public class Calculator { private Stack<IArithmeticInterpreter> stack = new Stack<IArithmeticInterpreter>(); public Calculator(String expression) { this.parse(expression); } private void parse(String expression) { String [] elements = expression.split(" "); IArithmeticInterpreter leftExpr, rightExpr; for (int i = 0; i < elements.length ; i++) { String operator = elements[i]; if (OperatorUtil.isOperator(operator)){ leftExpr = this.stack.pop(); rightExpr = new NumInterpreter(Integer.valueOf(elements[++i])); System.out.println("出栈: " + leftExpr.interpret() + " 和 " + rightExpr.interpret()); this.stack.push(OperatorUtil.getInterpreter(leftExpr, rightExpr,operator)); System.out.println("应用运算符: " + operator); } else{ NumInterpreter numInterpreter = new NumInterpreter(Integer.valueOf(elements[i])); this.stack.push(numInterpreter); System.out.println("入栈: " + numInterpreter.interpret()); } } } public int calculate() { return this.stack.pop().interpret(); } }
操作工具类:
public class OperatorUtil { public static boolean isOperator(String symbol) { return (symbol.equals("+") || symbol.equals("-") || symbol.equals("*")); } public static AbstractInterpreter getInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right, String symbol) { if (symbol.equals("+")) { return new AddInterpreter(left, right); } else if (symbol.equals("-")) { return new SubInterpreter(left, right); } else if (symbol.equals("*")) { return new MultiInterpreter(left, right); } else if (symbol.equals("/")) { return new DivInterpreter(left, right); } return null; } }
测试类:
public class Test { public static void main(String[] args) { System.out.println("result: " + new Calculator("10 + 30").calculate()); System.out.println("result: " + new Calculator("10 + 30 - 20").calculate()); System.out.println("result: " + new Calculator("100 * 2 + 400 * 1 + 66").calculate()); } }
六、解释器模式的优缺点
优点:
扩展性强:在解释器模式中由于语法是由很多类表示的,当语法规则更改时,只需修改相应的非终结符表达式即可;若扩展语法时,只需添加相应非终结符类即可;
增加了新的解释表达式的方式;
易于实现文法:解释器模式对应的文法应当是比较简单且易于实现的,过于复杂的语法并不适合使用解释器模式。
缺点:
语法规则较复杂时,会引起类膨胀:解释器模式每个语法都要产生一个非终结符表达式当语法规则比较复杂时,就会产生大量的解释类,增加系统维护困难;
执行效率比较低:解释器模式采用递归调用方法,每个非终结符表达式只关心与自己有关的表达式,每个表达式需要知道最终的结果,因此完整表达式的最终结果是通过从后往前递归调用的方式获取得到。当完整表达式层级较深时,解释效率下降,且出错时调试困难,因为递归迭代层级太深。
七、解释器模式在Spring源码中的应用
在 Spring 中,ExpressionParser 接口内部采用的也是解释器模式,它封装了字符串表达式的语法,源码如下。
package org.springframework.expression; public interface ExpressionParser { Expression parseExpression(String expressionString) throws ParseException; Expression parseExpression(String expressionString, ParserContext context) throws ParseException; }
ExpressionParser 不知道大家有没有用过,这里面也可以进行加减乘除运算。这里我们不深入讲解源码。如下是一个简单的应用示例:
package net.biancheng.c.interpreter; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; public class Test { public static void main(String[] args) { ExpressionParser parser = new SpelExpressionParser(); Expression expression = parser.parseExpression("100*2+400*1+66"); int result = (Integer) expression.getValue(); System.out.println("计算结果是:" + result); } }
运行结果如下
计算结果是:666
由运行结果可以看到,运行结果与预期结果是一致的。
解释器模式一般在业务开发中用的相对较少,常用的表达式都有人解析好了,直接用就可以了,除非我们从事底层开发需要自己去定义较为复杂的表达式。