化繁為簡的翻譯機——直譯器模式

HunterArley發表於2019-01-28

《Android原始碼設計模式解析與實戰》讀書筆記(十) 《Android原始碼設計模式解析與實戰》PDF資料下載

一、直譯器模式的簡介

直譯器模式是一種行為型模式,其提供了一種解釋語言的語法或表示式的方式,該模式定義了一個表示式介面,通過該介面解釋一個特定的上下文。

1.1、定義

給定一個語言,定義它的文法的一種表示,並定義一個直譯器,該直譯器使用該表示來解釋語言中的句子。

1.2、使用場景

  1. 如果某個簡單的語言需要解釋執行而且可以將該語言中的語句表示為一個抽象語法樹時可以考慮使用直譯器模式;
  2. 在某些特定的領域出現不斷重複的問題時,可以將該領域的問題轉化為一種語法規則下的語句,然後構建直譯器來解釋該語句。

二、直譯器模式的簡單實現

public abstract class ArithmeticExpression {
    /**
     * 抽象的解析方法
     * 具體的解析邏輯由具體的子類實現
     */
    public abstract int interpret();
}
複製程式碼
public class NumExpression extends ArithmeticExpression {
    private int num;

    public NumExpression(int num) {
        this.num = num;
    }

    @Override
    public int interpret() {
        return num;
    }
}
複製程式碼
public abstract class OperatorExpression extends ArithmeticExpression {
    //宣告兩個成員變數儲存格式兩邊的數字直譯器
    protected ArithmeticExpression exp1,exp2;

    public OperatorExpression(ArithmeticExpression exp1, ArithmeticExpression exp2) {
        this.exp1 = exp1;
        this.exp2 = exp2;
    }
}
複製程式碼
public class AdditionExpressiom extends OperatorExpression {
    public AdditionExpressiom(ArithmeticExpression exp1, ArithmeticExpression exp2) {
        super(exp1, exp2);
    }

    @Override
    public int interpret() {
        return exp1.interpret() + exp2.interpret();
    }
}
複製程式碼
public class Calcultator {
    //宣告一個Stack棧儲存並操作所有相關的直譯器
    private Stack<ArithmeticExpression> mExpStack = new Stack<>();

    public Calcultator(String expression) {
        //宣告兩個ArithmeticExpression型別的臨時變數,儲存運算子左右兩邊的數字直譯器
        ArithmeticExpression exp1, exp2;

        //根據空格分割表示式字串
        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.valueOf(elements[++i]));
                    //通過上面兩個數字直譯器構造加法運算直譯器
                    mExpStack.push(new AdditionExpressiom(exp1, exp2));
                    break;
                default://如果為數字
                    /**如果不是運算子則為數字
                     * 若是數字,直接構造數字直譯器並壓入棧
                     */
                    mExpStack.push(new NumExpression(Integer.valueOf(elements[i])));
                    break;
            }
        }
    }

    /**
     * 計算結果
     */
    public int calculate() {
        return mExpStack.pop().interpret();
    }
}
複製程式碼
Calcultator c = new Calcultator("153 + 3589 + 118 + 555");
        System.out.println(c.calculate());
複製程式碼

輸出結果:

4415
複製程式碼

三、總結

3.1、優點

直譯器模式最大的優點是其靈活的擴充套件性,當想對文法規則進行擴充套件延伸時,只需要增加相應的非終結符直譯器,並在構建抽象語法樹時,使用到新增的直譯器物件進行具體的解釋即可,非常方便。

3.2、缺點

因為對每一條文法都可以對應至少一個直譯器,其會生成大量的類,導致後期維護苦難。同時,過於複雜的文法,構建其抽象語法樹會顯得異常繁瑣,甚至有可能會出現需要構建多棵抽象語法樹的情況。因此,對於複雜的文法並不推薦使用直譯器模式。

學海無涯苦作舟

我的微信公眾號

相關文章