Java設計模式十四:解釋器模式(Interpreter)


解釋器模式定義語言的文法,並且建立一個解釋器來解釋該語言中的句子。它屬於類的行為模式。這里的語言意思是使用規定格式和語法的代碼。

應用環境:
如果一種特定類型的問題發生的頻率足夠高,那么可能就值得將該問題的各個實例表述為一個簡單語言中的句子。這樣就可以構建一個解釋器,該解釋器通過解釋這些句子來解決該問題。而且當文法簡單、效率不是關鍵問題的時候效果最好。

類圖:


抽象表達式角色(AbstractExpression): 聲明一個抽象的解釋操作,這個接口為所有具體表達式角色都要實現的.
終結符表達式角色(TerminalExpression): 實現與文法中的元素相關聯的解釋操作,通常一個解釋器模式中只有一個終結符表達式,但有多個實例對應不同的終結符.
終結符就是語言中用到的基本元素,一般不能再被分解,如: x -> xa, 這里a是終結符,因為沒有別的規則可以把a變成別的符號,不過x可以變成別的符號,所以x是非終結符.
非終結符表達式角色(NonterminalExpression): 文法中的每條規則對應於一個非終結表達式, 非終結表達式根據邏輯的復雜程度而增加,原則上每個文法規則都對應一個非終結符表達式.
環境角色(Context): 包含解釋器之外的一些全局信息.

實例:計算(a*b)/(a-b+2)
public class Context
{
    private final Map<String, Integer> valueMap = new HashMap<String, Integer>();

    public void addValue(final String key, final int value)
    {
        valueMap.put(key, Integer.valueOf(value));
    }

    public int getValue(final String key)
    {
        return valueMap.get(key).intValue();
    }
}

public abstract class AbstractExpression
{
    public abstract int interpreter(Context context);
}

public class AddNonterminalExpression extends AbstractExpression
{
    private final AbstractExpression left;
    private final AbstractExpression right;

    public AddNonterminalExpression(final AbstractExpression left, final AbstractExpression right)
    {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpreter(final Context context)
    {
        return this.left.interpreter(context) + this.right.interpreter(context);
    }

}

public class DivisionNonterminalExpression extends AbstractExpression
{
    private final AbstractExpression left;
    private final AbstractExpression right;

    public DivisionNonterminalExpression(final AbstractExpression left, final AbstractExpression right)
    {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpreter(final Context context)
    {
        final int value = this.right.interpreter(context);
        if (value != 0)
        {
            return this.left.interpreter(context) / value;
        }
        return -1111;
    }

}

public class MultiplyNonterminalExpression extends AbstractExpression
{
    private final AbstractExpression left;
    private final AbstractExpression right;

    public MultiplyNonterminalExpression(final AbstractExpression left, final AbstractExpression right)
    {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpreter(final Context context)
    {
        return this.left.interpreter(context) * this.right.interpreter(context);
    }

}

public class SubtractNonterminalExpression extends AbstractExpression
{
    private final AbstractExpression left;
    private final AbstractExpression right;

    public SubtractNonterminalExpression(final AbstractExpression left, final AbstractExpression right)
    {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpreter(final Context context)
    {
        return this.left.interpreter(context) - this.right.interpreter(context);
    }
}

public class TerminalExpression extends AbstractExpression
{
    private final int i;

    public TerminalExpression(final int i)
    {
        this.i = i;
    }

    @Override
    public int interpreter(final Context context)
    {
        return this.i;
    }

}

public class Client
{
    //(a*b)/(a-b+2)
    public static void main(final String[] args)
    {
        final Context context = new Context();
        context.addValue("a", 7);
        context.addValue("b", 8);
        context.addValue("c", 2);

        final MultiplyNonterminalExpression multiplyValue = new MultiplyNonterminalExpression(new TerminalExpression(
                context.getValue("a")), new TerminalExpression(context.getValue("b")));

        final SubtractNonterminalExpression subtractValue = new SubtractNonterminalExpression(new TerminalExpression(
                context.getValue("a")), new TerminalExpression(context.getValue("b")));

        final AddNonterminalExpression addValue = new AddNonterminalExpression(subtractValue, new TerminalExpression(
                context.getValue("c")));

        final DivisionNonterminalExpression divisionValue = new DivisionNonterminalExpression(multiplyValue, addValue);

        System.out.println(divisionValue.interpreter(context));
    }
}

結果:

56

優點:
解釋器是一個簡單語法分析工具,它最顯著的優點就是擴展性,修改語法規則只要修改相應的非終結符表達式就可以了,若擴展語法,則只要增加非終結符類就可以了。

缺點:
解釋器模式會引起類膨脹,每個語法都要產生一個非終結符表達式,語法規則比較復雜時,可能產生大量的類文件,難以維護。
解釋器模式采用遞歸調用方法,它導致調試非常復雜。
解釋器由於使用了大量的循環和遞歸,所以當用於解析復雜、冗長的語法時,效率是難以忍受的

注意事項:
盡量不要在重要模塊中使用解釋器模式,因為維護困難。在項目中,可以使用shell,JRuby,Groovy等腳本語言來代替解釋器模式。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM