24.Interpreter-解釋器模式

Interpreter 解釋器模式

  • 解釋器模式:
    定義一個語言的文法,並且建立一個解釋器來解釋該語言中的句子,這裏的“語言”是指使用規定格式和語法的代碼。
    解釋器模式是一種類行爲型模式。 由於表達式可分爲終結符表達式和非終結符表達式,
    因此解釋器模式的結構與組合模式的結構有些類似,但在解釋器模式中包含更多的組成元素。

  • 結構圖:
    Interpreter_structure

  • 示例類圖:
    Interpreter_uml

  • 示例代碼:

// Expression
public interface Expression {
    public void interpret(Context context);
}

// AbstractExpression
public abstract class AbstractExpression implements Expression {
    protected static List<String> table;

    public AbstractExpression() {
        if (null == table) {
            initTable();
        }
    }

    public void initTable() {
        table = new ArrayList<String>();
        table.add("一");
        table.add("二");
        table.add("三");
        table.add("四");
        table.add("五");
        table.add("六");
        table.add("七");
        table.add("八");
        table.add("九");
    }

    public void interpret(Context context) {
        String statement = context.getStatement();
        System.out.println(statement);
        if (null == statement || statement.isEmpty())
            return;

        for (int i = 0; i < table.size(); i++) {
            String tail = table.get(i) + this.getPostfix();
            // 從低位往高位分析,即從右往左
            if (statement.endsWith(tail)) {
                int newData = context.getData() + (i + 1) * this.multiplier();
                context.setData(newData);
                context.setStatement(statement.substring(0, statement.length() - tail.length()));
            }

            if (statement.endsWith("零")) {
                context.setStatement(statement.substring(0, statement.length() - "零".length()));
            }
        }
    }

    // 表達式的後綴是以什麼表示的 十,百,千...
    public abstract String getPostfix();

    // 表達式的數量級
    public abstract int multiplier();
}

// TerminalExpression 個位數解釋器
public class ExpressionGe extends AbstractExpression {

    @Override
    public String getPostfix() {
        return "";
    }

    @Override
    public int multiplier() {
        return 1;
    }
}
// TerminalExpression 十位數解釋器
public class ExpressionShi extends AbstractExpression {

    @Override
    public String getPostfix() {
        return "十";
    }

    @Override
    public int multiplier() {
        return 10;
    }
}
// TerminalExpression 百位數解釋器
public class ExpressionBai extends AbstractExpression {

    @Override
    public String getPostfix() {
        return "百";
    }

    @Override
    public int multiplier() {
        return 100;
    }
}
// TerminalExpression 千位數解釋器
public class ExpressionQian extends AbstractExpression {

    @Override
    public String getPostfix() {
        return "千";
    }

    @Override
    public int multiplier() {
        return 1000;
    }
}

// NonterminalExpression 萬位數解釋器
public class ExpressionWan extends AbstractExpression {
    private static List<Expression> expressions = new ArrayList<Expression>();

    public ExpressionWan() {
        if (expressions.isEmpty()) {
            expressions.add(new ExpressionGe());
            expressions.add(new ExpressionShi());
            expressions.add(new ExpressionBai());
            expressions.add(new ExpressionQian());
        }
    }

    @Override
    public void interpret(Context context) {
        String statement = context.getStatement();
        if (null == statement || statement.isEmpty())
            return;

        if (statement.endsWith(this.getPostfix())) {
            context.setStatement(statement.substring(0, statement.length() - getPostfix().length()));
            int data = context.getData();
            context.setData(0);// 置零
            for (Expression expression : expressions) {
                expression.interpret(context);
            }
            context.setData(data + this.multiplier() * context.getData());
        }
    }

    @Override
    public String getPostfix() {
        return "萬";
    }

    @Override
    public int multiplier() {
        return 10000;
    }
}

// 將中文數字串由低位向高位方向不斷轉化
public class Convertor {
    private static List<Expression> expressions = new ArrayList<Expression>();

    public Convertor() {
        if (expressions.isEmpty()) {
            expressions.add(new ExpressionGe());
            expressions.add(new ExpressionShi());
            expressions.add(new ExpressionBai());
            expressions.add(new ExpressionQian());
            expressions.add(new ExpressionWan());
        }
    }

    public int convert(String chineseNum) {
        Context context = new Context(chineseNum);
        for (Expression expression : expressions) {
            expression.interpret(context);
        }
        return context.getData();
    }
}

// 測試
public class ExpressionTest {
    public static void main(String[] args) {
        String chineseNum = "六百三十七萬八千二百零一";// 6378201
        Convertor convertor = new Convertor();
        System.out.println(chineseNum);
        System.out.println(convertor.convert(chineseNum));

        System.out.println(convertor.convert("五百萬"));
    }
}
  1. Context:上下文,通常包含各個解釋器需要的數據或是公共的功能。
    這個Context在解釋器模式中起着非常重要的作用。
    一般用來傳遞被所有解釋器共享的數據,後面的解釋器可以從這裏獲取這些值。

  2. AbstractExpression: 定義解釋器的接口/抽象類,約定解釋器的解釋操作。
    其中的Interpret接口,正如其名字那樣,它是專門用來解釋該解釋器所要實現的功能。
    (如加法解釋器中的Interpret接口就是完成兩個操作數的相加功能)。

  3. TerminalExpression: 終結符解釋器,用來實現語法規則中和終結符相關的操作,
    不再包含其他的解釋器,如果用組合模式來構建抽象語法樹的話,
    就相當於組合模式中的葉子對象,可以有多種終結符解釋器。

  4. NonterminalExpression: 非終結符解釋器,用來實現語法規則中非終結符相關的操作,
    通常一個解釋器對應一個語法規則,可以包含其他解釋器,如果用組合模式構建抽象語法樹的話,
    就相當於組合模式中的組合對象。可以有多種非終結符解釋器。

    • 缺點:
  5. 執行效率較低。由於在解釋器模式中使用了大量的循環和遞歸調用,
    因此在解釋較爲複雜的句子時其速度很慢,而且代碼的調試過程也比較麻煩。

  6. 對於複雜文法難以維護。在解釋器模式中,每一條規則至少需要定義一個類,
    因此如果一個語言包含太多文法規則,類的個數將會急劇增加,導致系統難以管理和維護,
    此時可以考慮使用語法分析程序等方式來取代解釋器模式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章