一、解释器模式定义
1.解释器模式是指给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。是一种按照规定的语法(文法)进行解析的模式,属于行为型模式。
2.其核心思想是识别文法,构建解释。分离终结符号和非终结符号,提取出需要的信息
3.解释器模式的应用场景:
A.一些重复出现的问题可以用一种简单的语言来进行表达
B.一个简单语法需要解释的场景
二、解释器模式示例
1.解释器模式一般包含4种角色:
A.抽象表达式(Expression):负责定义一个解释方法interpret,交由具体子类进行具体解释
B.终结符表达式(TerminalExpression):实现文法中与终结符有关的解释操作。文法中的每一个终结符都有一个具体终结表达式与之相对应,比如公式R=R1+R2,R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符(R1,R2)
C.非终结符表达式(NonterminalExpression):实现文法中与非终结符有关的解释操作。文法中的每条规则都对应于一个非终结符表达式。非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,"+"就是非终结符,解析"+"的解释器就是一个非终结符表达式。非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式
D.上下文环境类(Context):包含解释器之外的全局信息。它的任务一般是用来存放文法中各个终结符所对应的具体的值,比如R=R1+R2,给R1赋值100,给R2赋值200,这些信息需要存放到环境中
2.代码示例
1 public interface IArithmeticInterpreter { 2 int interpret(); 3 } 4 5 public abstract class Interpreter implements IArithmeticInterpreter { 6 7 protected IArithmeticInterpreter left; 8 protected IArithmeticInterpreter right; 9 10 public Interpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) { 11 this.left = left; 12 this.right = right; 13 } 14 } 15 16 public class AddInterpreter extends Interpreter { 17 18 public AddInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) { 19 super(left, right); 20 } 21 22 public int interpret() { 23 return this.left.interpret() + this.right.interpret(); 24 } 25 } 26 27 public class SubInterpreter extends Interpreter { 28 public SubInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) { 29 super(left, right); 30 } 31 32 public int interpret() { 33 return this.left.interpret() - this.right.interpret(); 34 } 35 } 36 37 public class MultiInterpreter extends Interpreter { 38 39 public MultiInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right){ 40 super(left,right); 41 } 42 43 public int interpret() { 44 return this.left.interpret() * this.right.interpret(); 45 } 46 47 } 48 49 public class DivInterpreter extends Interpreter { 50 51 public DivInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right){ 52 super(left,right); 53 } 54 55 public int interpret() { 56 return this.left.interpret() / this.right.interpret(); 57 } 58 59 } 60 61 public class NumInterpreter implements IArithmeticInterpreter { 62 private int value; 63 64 public NumInterpreter(int value) { 65 this.value = value; 66 } 67 68 69 public int interpret() { 70 return this.value; 71 } 72 } 73 74 public class GPCalculator { 75 private Stack<IArithmeticInterpreter> stack = new Stack<IArithmeticInterpreter>(); 76 77 public GPCalculator(String expression) { 78 this.parse(expression); 79 } 80 81 private void parse(String expression) { 82 String [] elements = expression.split(" "); 83 IArithmeticInterpreter leftExpr, rightExpr; 84 85 for (int i = 0; i < elements.length ; i++) { 86 String operator = elements[i]; 87 if (OperatorUtil.isOperator(operator)){ 88 leftExpr = this.stack.pop(); 89 rightExpr = new NumInterpreter(Integer.valueOf(elements[++i])); 90 System.out.println("出栈: " + leftExpr.interpret() + " 和 " + rightExpr.interpret()); 91 this.stack.push(OperatorUtil.getInterpreter(leftExpr, rightExpr,operator)); 92 System.out.println("应用运算符: " + operator); 93 } 94 else{ 95 NumInterpreter numInterpreter = new NumInterpreter(Integer.valueOf(elements[i])); 96 this.stack.push(numInterpreter); 97 System.out.println("入栈: " + numInterpreter.interpret()); 98 } 99 } 100 } 101 102 public int calculate() { 103 return this.stack.pop().interpret(); 104 } 105 } 106 107 public class OperatorUtil { 108 109 public static boolean isOperator(String symbol) { 110 return (symbol.equals("+") || symbol.equals("-") || symbol.equals("*")); 111 } 112 113 public static Interpreter getInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right, String symbol) { 114 if (symbol.equals("+")) { 115 return new AddInterpreter(left, right); 116 } else if (symbol.equals("-")) { 117 return new SubInterpreter(left, right); 118 } else if (symbol.equals("*")) { 119 return new MultiInterpreter(left, right); 120 } else if (symbol.equals("/")) { 121 return new DivInterpreter(left, right); 122 } 123 return null; 124 } 125 } 126 127 public class Test { 128 129 public static void main(String[] args) { 130 System.out.println("result: " + new GPCalculator("10 + 30").calculate()); 131 System.out.println("result: " + new GPCalculator("10 + 30 - 20").calculate()); 132 System.out.println("result: " + new GPCalculator("100 * 2 + 400 * 1 + 66").calculate()); 133 } 134 135 }
3.解释器模式的优缺点
A.优点
a.扩展性强:在解释器模式中由于语法是由很多类表示的,当语法规则更改时,只需修改相应的非终结符表达式即可;若扩展语法时,只需添加相应非终结符类即可
b.增加了新的解释表达式的方式
c.易于实现文法:解释器模式对应的文法应当是比较简单且易于实现的,过于复杂的语法并不适合使用解释器模式
B.缺点
a.语法规则较复杂时,会引起类膨胀:解释器模式每个语法都要产生一个非终结符表达式,当语法规则比较复杂时,就会产生大量的解释类,增加系统维护难度
b.执行效率比较低:解释器模式采用递归调用方法,每个非终结符表达式只关心与自己有关的表达式,每个表达式需要知道最终的结果,因此完整表达式的最终结果是通过从后往前递归调用的方式获取得到。当完整表达式层级较深时,解释效率下降,且出错时调试困难,因为递归迭代层级太深