解释器模式
定义
Given a language,define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language
给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
解释器模式示意图
流程
定义一个总的抽象表达式类,是所有表达式的父类。表达式又分为变量表达式和符号表达式。
变量表达式需要输入公式变量与数字的映射关系,通过映射关系用公式变量取出对应的具体数字,将具体数字套入公式。
抽象符号表达式类是所有符号运算类的父类,符号运算包括加减乘除的运算规则。
通过客户端提供公式以及公式变量与数字的映射关系,将这两个输入计算器对象中,按多态性来根据公式符号选择需要的符号解释器,将公式变量与数字的映射关系输入变量解释器,将对应的数字套入结果表达式中,获取最终结果。
代码实现
表达式
抽象表达式Expression
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package org.example.interpreter;import java.util.HashMap;public abstract class Expression { public abstract int interpreter (HashMap<String , Integer> var ) ; }
变量表达式VarExpression
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package org.example.interpreter;import java.util.HashMap;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(key); } }
抽象符号表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package org.example.interpreter;import java.util.HashMap;public abstract class SymbolExpression extends Expression { protected Expression left ; protected Expression right ; public SymbolExpression (Expression left , Expression right) { this .left = left ; this .right = right ; } }
加法表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package org.example.interpreter;import java.util.HashMap;public class AddExpression extends SymbolExpression { public AddExpression (Expression left, Expression right) { super (left, right); } @Override public int interpreter (HashMap<String, Integer> var ) { return super .left.interpreter(var ) + super .right.interpreter(var ); } }
减法表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package org.example.interpreter;import java.util.HashMap;public class SubExpression extends SymbolExpression { public SubExpression (Expression left, Expression right) { super (left, right); } @Override public int interpreter (HashMap<String, Integer> var ) { return super .left.interpreter(var ) - super .right.interpreter(var ); } }
乘法表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package org.example.interpreter;import java.util.HashMap;public class MulExpression extends SymbolExpression { public MulExpression (Expression left, Expression right) { super (left, right); } @Override public int interpreter (HashMap<String, Integer> var ) { return super .left.interpreter(var ) * super .right.interpreter(var ) ; } }
除法表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package org.example.interpreter;import java.util.HashMap;public class DivExpression extends SymbolExpression { public DivExpression (Expression left, Expression right) { super (left, right); } @Override public int interpreter (HashMap<String, Integer> var ) { return super .left.interpreter(var ) / super .right.interpreter(var ) ; } }
计算器
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 package org.example.interpreter;import java.util.HashMap;import java.util.Stack;public class Calculator { private Expression expression ; public Calculator (String expStr) { Stack<Expression> stack = new Stack<>(); Expression left = null ; Expression right = null ; System.out.println(expStr); char [] array = expStr.toCharArray(); for (int i=0 ; i<array.length ; i++){ switch (array[i]){ case '+' : left = stack.pop(); right = new VarExpression(String.valueOf(array[++i])); stack.push(new AddExpression(left , right)); break ; case '-' : left = stack.pop(); right = new VarExpression(String.valueOf(array[++i])); stack.push(new SubExpression(left , right)) ; break ; case '*' : left = stack.pop(); right = new VarExpression(String.valueOf(array[++i])); stack.push(new MulExpression(left , right)) ; break ; case '/' : left = stack.pop() ; right = new VarExpression(String.valueOf(array[++i])); stack.push(new DivExpression(left , right)) ; break ; default : stack.push(new VarExpression(String.valueOf(array[i]))) ; break ; } } this .expression = stack.pop() ; } public int run (HashMap<String , Integer> var ) { return this .expression.interpreter(var ) ; } }
场景实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class App { public static void main (String[] args) { HashMap<String, Integer> map = new HashMap<>(); map.put("a" , 100 ); map.put("b" , 20 ); map.put("c" , 30 ); String expStr = "a+b-c" ; Calculator calculator = new Calculator(expStr); System.out.println(calculator.run(map)); } }
应用场景
重复发生的问题,规则不同,但是有相同的元素,久可以使用解释器模式。
一个简单语法需要解释。如果是复杂语法,会导致类膨胀。
解释器模式的优缺点
优点
解释器是一个简单的语法分析工具,优点是扩展性,修改语法规则只需要修改对应的符号表达式就行了。
缺点
会引起类膨胀,每种语法都会产生一个规则类,语法规则很复杂时会产生很多规则类。
解释器模式采用递归调用,使用栈。调试非常麻烦。
解释器模式使用递归和栈,效率很低。
注意事项
不要在重要模块使用解释器模式,这样会导致很难维护。
解释器模式在实际中很少使用,主要在数据分析工具、报表设计工具、科学计算工具使用。
可以使用Expression4J,MESP,Jep开源解析工具来代替自己写解释器模式。