1. 程式人生 > >面向對象的設計模式(十三),解釋器模式

面向對象的設計模式(十三),解釋器模式

bst doc BE private integer 回來 import new 得到

解釋器模式,從字面上解釋來說就是為一個文法(具有特定語法的形式的語句或表達式)構造解釋器,這個解釋器用來解釋這個文法,使得這樣的具有某種書寫規則的文法能夠表示特定的功能,這樣的特定書寫規則也就是通常所說的語法,如C/C++,Java,Python等計算機語言有自己的語法。還有,一些解釋型語言如Python。它在執行的時候須要Python解釋器,這也就是一種解釋器。

定義:解釋器模式為一些具有特定書寫規則的文法編寫解釋器,從而使得它具有某種意義。

使用場景:

  1. 作為解釋器

    解釋具有特定語法的語句的功能或者意義。如解釋具有特定書寫規則的語句,在以下的這個樣例中就是作為解釋器來解釋運算表達式。

  2. 作為翻譯機或者譯碼器。如高級語言中的常量,編譯的時候編譯器系統會將常量替換成它代表的數一樣,相似的我們也能夠定義一些特定的具有某種意義的語句。然後用對應的解釋器來解釋器它。

假設又這麽個表達式或語句a_+_b_-_c,我們想要知道它的意思,假如我們規定_符號用來分隔數字和運算符,那麽上面的這個語句表達的意思就是計算a+b-c。這和學生考試的時候。它們規定1表示A,2表示B,3表示C,4表示D來傳選擇題答案一樣的,相似於編碼譯碼過程。事實上譯碼器也就是解釋器,那麽我們通過代碼來解釋上面表達式的意思。

代碼實現:

抽象解釋器(基類)

/**
 * 主要的解釋器。是全部解釋器的基類
 * @author
lt * */
public abstract class BaseInterpreter<T> { /** * 抽象解釋方法 * @return */ public abstract T interpret(); }

?抽取了解釋器的共性

整數解釋器(解釋整數)

/**
 * 整數解釋器
 * @author lt
 *
 */
public class NumberInterpreter extends BaseInterpreter<Integer>{

    private int num;

    public
NumberInterpreter(int num){ this.num = num; } @Override public Integer interpret() { return this.num; // 自己主動裝箱拆箱 } }

?解釋整數,直接返回這個整數。這裏的整數也就是終結符

運算符解釋器(基類

/**
 * 二目運算符操作解釋器,也是一個基類,由於有好多的二目運算符
 * @author lt
 *
 */
public abstract class OperatorInterpreter extends BaseInterpreter<Integer>{

    protected BaseInterpreter<Integer> exp1;
    protected BaseInterpreter<Integer> exp2;

    public OperatorInterpreter(BaseInterpreter<Integer> exp1,BaseInterpreter<Integer> exp2){
        this.exp1 = exp1;
        this.exp2 = exp2;
    }

}

?解釋二目運算符。須要兩個整數,為非終結符解釋器。

加法解釋器(計算加法)

/**
 * 加法解釋器。計算加法
 * @author lt
 *
 */
public class AdditionInterpreter extends OperatorInterpreter{

    public AdditionInterpreter(BaseInterpreter<Integer> exp1,
            BaseInterpreter<Integer> exp2) {
        super(exp1, exp2);
    }

    /**
     * 用來計算加法
     */
    @Override
    public Integer interpret() {
        return exp1.interpret() + exp2.interpret();
    }
}

減法解釋器(計算減法)

/**
 * 減法計算器
 * @author lt
 *
 */
public class SubtractionInterpreter extends OperatorInterpreter{

    public SubtractionInterpreter(BaseInterpreter<Integer> exp1,
            BaseInterpreter<Integer> exp2) {
        super(exp1, exp2);
    }

    @Override
    public Integer interpret() {
        return exp1.interpret() - exp2.interpret();
    }
}

計算器,翻譯a_+_b_-_c(計算表達式)

import java.util.Stack;

/**
 * 計算器
 * @author lt
 *
 */
public class Calculator {

    private Stack<BaseInterpreter<Integer>> mExpStack = new Stack<BaseInterpreter<Integer>>();

    public Calculator(String expression){
        // 聲明兩個BaseInterpreter<Integer>的暫時變量,由於計算必須要記錄兩個數
        BaseInterpreter<Integer> exp1,exp2;

        //  以符號_分隔,這是我們自己規定的
        String[] exps = expression.split("_");

        for(int i=0;i<exps.length;i++){
            switch (exps[i].charAt(0)) {
            case ‘+‘: // 加法
                exp1 = mExpStack.pop();
                exp2 = new NumberInterpreter(Integer.valueOf(exps[++i]));
                mExpStack.push(new AdditionInterpreter(exp1, exp2));
                break;
            case ‘-‘:
                exp1 = mExpStack.pop();
                exp2 = new NumberInterpreter(Integer.valueOf(exps[++i]));
                mExpStack.push(new SubtractionInterpreter(exp1, exp2));
                break;
            default: // 數字
                mExpStack.push(new NumberInterpreter(Integer.valueOf(exps[i])));
                break;
            }
        }
    }

    /**
     * 計算
     * @return
     */
    public int calculate(){
        return mExpStack.pop().interpret();
    }
}

?這個類用來翻譯a_+_b_-_c等形式結構的語句的意思。這裏的符號_是我規定用來分隔數字的,當然你也能夠規定其它符號作為分隔符。

這個類的方法也非常easy,構造方法中先是將表達式按符號_分隔。得到一些運算符和數字,然後在依據分隔出來的字符串的第一個字符的類型推斷是+運算符還是-運算符還是數字,假設是+運算符。那麽就將存儲的上一個數字彈出棧並記錄到exp1,然後得到運算符後面的那個字符串(肯定是數字)並記錄到變量exp2中。最後用加法解釋器解釋這兩個變量記錄的數字並壓入棧,等下一次循環的時候彈出和下一個數字進行計算;假設是-運算符,那麽和+運算符是一樣的,僅僅只是用的是減法解釋器;假設是數字,直接壓入棧,整個過程是逐步計算的過程。calculate方法用來輸出計算結果。

測試

public class Test {

    public static void main(String[] args) {
        String testStr = "1_+_34_-_10_+_50";
        Calculator calculator = new Calculator(testStr);
        System.out.println("result="+calculator.calculate());
    }
}

結果:

技術分享圖片

?能夠看到我們定義的解釋器成功解釋了a_+_b_-_c這樣的形式的語句,事實上這個解釋器實現的功能相似譯碼的功能或者翻譯的功能。只是話說回來,盡管是成功解釋了那種形式的語句,可是也僅僅能計算整數的加減法。假設想要做其它運算或者其它類型的數字,如乘除法和浮點型,那麽須要加入對應的解釋器,但假設涉及到混合運算的時候,那復雜多了,還得考慮優先級。這個時候這樣的模式可能就不適合了,也就是說解釋器模式適合於簡單的語句。

總結

長處:

  • 靈活的擴展性

    當我們對語法規則擴展延伸適合,僅僅須要加入對應的非終結符解釋器(如上面的加減法解釋器),並在構建抽象語法樹時,使用到新添加的解釋器對象(如加入減法解釋器)進行詳細的解釋(計算減法)就可以,非常方便。非終結符也就是還沒有結束的符號,如以下樣例中的加法和減法解釋器分別解釋的加好和減號一樣,它們是二目運算符。其兩邊肯定要兩個數。

缺點:

  • 類數量膨脹,後期維護困難。由於對於每一條文法都對應至少一個解釋器類,會產生大量的類,導致後期維護困難。同一時候,對於復雜的文法,構建其抽象的語法樹會顯得比較繁瑣,甚至須要構建多顆語法樹,因此。對於復雜的文法並不推薦使用解釋器模式。

面向對象的設計模式(十三),解釋器模式