天天看點

22解釋器模式

一、解釋器模式定義

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.易于實作文法:解釋器模式對應的文法應當是比較簡單且易于實作的,過于複雜的文法并不适合使用解釋器模式