標籤:key pack code express 分離 特定 lex value type
第十章、解譯器模式
解譯器模式是一種用的比較少的行為型模式。其提供了一種解釋語言的文法或運算式的方式。
可是它的使用情境確實非常廣泛,僅僅是由於我們自己非常少回去構造一個語言的文法,所以使用較少。
1.定義
給定一個語言,定義它的文法的一種表示,並定義一個解譯器,該解譯器使用該表示來解釋語言中的句子。
(當中語言就是我們須要解釋的對象,文法就是這個語言的規律,解譯器就是翻譯機。通過文法來翻譯語言。)
2.使用情境
1.假設某個簡單的語言須要解釋運行並且能夠將該語言中的語句表示為一個抽象的文法樹時能夠考慮使用解譯器模式。
2.在某些特定的領域出現不斷反覆的問題時,能夠將該領域的問題轉化為一種文法規則下的語句。然後構建解譯器來解釋該語句。
3.簡單實現
我們使用解譯器模式對“m+n+p”這個運算式進行解釋,那麼代表數位m、n和p就能夠看成終結符號,而“+”這個運算子號能夠當做非終結符號。
TerminalExpression:終結符運算式,實現文法中與終結符有關的解釋操作。
文法中每一個終結符都有一個詳細的終結運算式與之相應。
NonterminalExpression :非終結符運算式,實現文法中與非終結符有關的解釋操作。非終結符運算式依據邏輯的複雜程度而添加。原則上每一個文法規則都相應一個非終結符運算式。
抽象的算數運算解譯器
public abstract class ArithemticExpression { /** * 抽象的解析方法 * 詳細的解析邏輯由詳細的子類實現 * * @return 解析得到詳細的值 */ public abstract int interpreter();}
數字解譯器
public class NumExpression extends ArithemticExpression{ private int num; public NumExpression(int num){ this.num = num; } @Override public int interpreter() { return num; }}
運算子號解譯器
public abstract class OperatorExpression extends ArithemticExpression{ protected ArithemticExpression exp1, exp2; public OperatorExpression(ArithemticExpression exp1, ArithemticExpression exp2){ this.exp1 = exp1; this.exp2 = exp2; }}
詳細的加法運算子解譯器
public class AdditionExpression extends OperatorExpression{ public AdditionExpression(ArithemticExpression exp1, ArithemticExpression exp2) { super(exp1, exp2); } @Override public int interpreter() { return exp1.interpreter() + exp2.interpreter(); }}
處理解譯器
public class Calculator { //聲明一個Stack棧儲存並操作全部相關的解譯器 private Stack<ArithemticExpression> mExpStack = new Stack<ArithemticExpression>(); public Calculator(String expression){ //聲明兩個ArithemticExpression類型的暫時變數,儲存運算子左右兩邊的數字解譯器 ArithemticExpression exp1,exp2; //依據空格切割運算式字串(比方1 + 2 + 3 + 4) String[] elements = expression.split(" "); /* * 遍曆運算式元素數組 */ for(int i = 0; i < elements.length; i++){ /* * 推斷運算子號 */ switch (elements[i].charAt(0)) { case ‘+‘: //假設是加號,則將棧中的解譯器彈出作為運算子號左邊的解譯器 exp1 = mExpStack.pop(); //同一時候將運算子號數組下標的下一個元素構造為一個數字解譯器 exp2 = new NumExpression(Integer.parseInt(elements[++i])); //通過上面的兩個數字解譯器構造加法運算解譯器 mExpStack.push(new AdditionExpression(exp1, exp2)); break; default: /* * 假設為數字,直接構造數字解譯器並壓入棧 */ mExpStack.push(new NumExpression(Integer.valueOf(elements[i]))); break; } } } /** * 計算結果 * * @return 終於的計算結果 */ public int calculate(){ return mExpStack.pop().interpreter(); }}
調用
public class Client { public static void main(String[] args) { Calculator c = new Calculator("22 + 553 + 83 + 5"); System.out.println("計算結果:"+c.calculate()); }}
結果:
計算結果:663
假設相加如減法的操作,在Calculator中添加相應推斷就可以:
public class SubtractionExpression extends OperatorExpression{ public SubtractionExpression(ArithemticExpression exp1, ArithemticExpression exp2) { super(exp1, exp2); } @Override public int interpreter() { return exp1.interpreter() - exp2.interpreter(); }}
Calculator中添加:
case ‘-‘: exp1 = mExpStack.pop(); exp2 = new NumExpression(Integer.parseInt(elements[++i])); mExpStack.push(new SubtractionExpression(exp1, exp2)); break;
從上面能夠看出解譯器模式非常靈活,他將複雜問題能夠簡單化、模組化、分離實現、解釋運行。
4.Android原始碼中的模式實現1.PackageParser
PackageParser是對AndroidManifest.xml設定檔進行讀取的,詳細原理參考:解析AndroidManifest原理
5.總結1.長處
最大的長處使其靈活的擴充性,當我們想對文法規則進行擴充延伸時。僅僅須要添加相應的非終結符解譯器,並在構建抽象文法樹時。使用到新增的解譯器對象進行詳細的解釋就可以,非常方便。
2.缺點
1.每一個文法都要產生一個非終結符運算式,文法規則比較複雜時。就可能產生大量的類檔案,為維護帶來了非常多的麻煩。
2.解譯器模式由於使用了大量的迴圈和遞迴。效率是個問題,特別是用於解析複雜、冗長的文法時,效率是難以忍受的。
6.參考
參考連結:解譯器模式 詳細解釋
《Android原始碼設計模式解析與實戰》讀書筆記(十)