解釋器模式

  給定其中一種語言,解釋器模式能夠定義出其文本的一種表示,並同時提供一個解釋器。客戶端可使用這個解釋器來解釋這個語言中的句子。java

 

爲了說明解釋器模式的實現辦法,這裏給出一個最簡單的文法和對應的解釋器模式的實現,模擬Java語言中對布爾表達式進行操做和求值。
  在這個語言中終結符是布爾變量,也就是常量true和false。非終結符表達式包含運算符and,or和not等布爾表達式。這個簡單的文法以下:
    Expression ::= Constant | Variable | Or | And | Not
    And     ::= Expression 'AND' Expression
    Or     ::= Expression 'OR' Expression
    Not     ::= 'NOT' Expression
    Variable  ::= 任何標識符
    Constant ::= 'true' | 'false'‘’express

  抽象語法樹(AST)的每個節點都表明一個語句,而在每個節點上均可以執行解釋方法。這個解釋方法的執行就表明這個語句被解釋。因爲每個語句都表明一個常見的問題的實例,所以每個節點上的解釋操做都表明對一個問題實例的解答。ide

 

 結構:

 其結構以下:this

 

角色:

(1)抽象表達式角色(expression):聲明一個全部的具體表達式都須要實現的抽象接口。這個接口主要是一個interpret()方法,稱做解釋方法。spa

(2)終結符表達式(Terminal Expression):這是一個具體表達式。好比 A and B 中的 a、b就是一個終結符表達式code

實現了上述抽象表達式角色聲明的接口,主要是一個interpret()方法;blog

文法中的每個終結符都有一個具體終結表達式與之對應。遞歸

(3)非終結表達式(Nonterminal Expression):一個具體角色。好比 A and B 中的 and就是一個終結符表達式接口

文法中的每一條規則R=R1R2R3...Rn都須要一個具體的非終結符表達式;字符串

對每個R1R2R3...Rn中的符號都持有一個靜態類型爲Expression的實例變量;

實現解釋操做,即interpret()方法。解釋操做以遞歸方式調用上面的R1R2R3...Rn中的各個符號的實例變量。

(4)客戶端角色:構造一個抽象語法樹(AST或AbstractSyntaxTree);調用解釋操做interpret()

(5)環境角色(Context):提供解釋器以外的一些全局信息,好比變量的真實量值等。

 

源碼以下:

抽象表達式角色:

package expression;

public abstract class Expression {
    /**
     * 以環境爲準,本方法解釋給定的任何一個表達式
     */
    public abstract boolean interpret(Context ctx);

    /**
     * 檢驗兩個表達式在結構上是否相同
     */
    public abstract boolean equals(Object obj);

    /**
     * 返回表達式的hash code
     */
    public abstract int hashCode();

    /**
     * 將表達式轉換成字符串
     */
    public abstract String toString();
}

 

Constant常量表明一個布爾常量:

package expression;

public class Constant extends Expression {

    private boolean value;

    public Constant(boolean value) {
        this.value = value;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj != null && obj instanceof Constant) {
            return this.value == ((Constant) obj).value;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.toString().hashCode();
    }

    @Override
    public boolean interpret(Context ctx) {
        return value;
    }

    @Override
    public String toString() {
        return new Boolean(value).toString();
    }

}

 

Variable表明有名變量,在使用Variable類時,須要將變量名傳入構造中:

package expression;

public class Variable extends Expression {

    private String name;

    public Variable(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj != null && obj instanceof Variable) {
            return this.name.equals(((Variable) obj).name);
        }

        return false;
    }

    @Override
    public int hashCode() {
        return this.toString().hashCode();
    }

    @Override
    public String toString() {
        return name;
    }

    @Override
    public boolean interpret(Context ctx) {
        return ctx.lookup(this);
    }

}

 

表明邏輯「與」操做的And類,表示由兩個布爾表達式經過邏輯「與」操做給出一個新的布爾表達式的操做

package expression;

public class And extends Expression {

    private Expression left, right;

    public And(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj != null && obj instanceof And) {
            return left.equals(((And) obj).left) && right.equals(((And) obj).right);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.toString().hashCode();
    }

    @Override
    public boolean interpret(Context ctx) {
        return left.interpret(ctx) && right.interpret(ctx);
    }

    @Override
    public String toString() {
        return "(" + left.toString() + " AND " + right.toString() + ")";
    }

}

 

表明邏輯「或」操做的Or類,表明由兩個布爾表達式經過邏輯「或」操做給出一個新的布爾表達式的操做

package expression;

public class Or extends Expression {
    private Expression left, right;

    public Or(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj != null && obj instanceof Or) {
            return this.left.equals(((Or) obj).left) && this.right.equals(((Or) obj).right);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.toString().hashCode();
    }

    @Override
    public boolean interpret(Context ctx) {
        return left.interpret(ctx) || right.interpret(ctx);
    }

    @Override
    public String toString() {
        return "(" + left.toString() + " OR " + right.toString() + ")";
    }

}

 

表明邏輯「非」操做的Not類,表明由一個布爾表達式經過邏輯「非」操做給出一個新的布爾表達式的操做

package expression;

public class Not extends Expression {

    private Expression exp;

    public Not(Expression exp) {
        this.exp = exp;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj != null && obj instanceof Not) {
            return exp.equals(((Not) obj).exp);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.toString().hashCode();
    }

    @Override
    public boolean interpret(Context ctx) {
        return !exp.interpret(ctx);
    }

    @Override
    public String toString() {
        return "(Not " + exp.toString() + ")";
    }

}

 

環境(Context)類定義出從變量到布爾值的一個映射

package expression;

import java.util.HashMap;
import java.util.Map;

public class Context {

    private Map<Variable, Boolean> map = new HashMap<Variable, Boolean>();

    public void assign(Variable var, boolean value) {
        map.put(var, new Boolean(value));
    }

    public boolean lookup(Variable var) throws IllegalArgumentException {
        Boolean value = map.get(var);
        if (value == null) {
            throw new IllegalArgumentException();
        }

        return value.booleanValue();
    }
}

 

客戶端:

package expression;

public class Client {

    public static void main(String[] args) {
        Variable x = new Variable("x");
        Variable y = new Variable("y");

        Context ctx = new Context();
        ctx.assign(x, false);
        ctx.assign(y, true);
        System.out.println("x=" + x.interpret(ctx));
        System.out.println("y=" + y.interpret(ctx));

        Constant c = new Constant(true);
        Expression exp = new Or(new And(c, x), new And(y, new Not(x)));
        System.out.println(exp.toString() + "=" + exp.interpret(ctx));
    }

}

結果:

x=false
y=true
((true AND x) OR (y AND (Not x)))=true

 

總結:

意圖:給定一個語言,定義它的文法表示,並定義一個解釋器,這個解釋器使用該標識來解釋語言中的句子。

主要解決:對於一些固定文法構建一個解釋句子的解釋器。

什麼時候使用:若是一種特定類型的問題發生的頻率足夠高,那麼可能就值得將該問題的各個實例表述爲一個簡單語言中的句子。這樣就能夠構建一個解釋器,該解釋器經過解釋這些句子來解決該問題。

如何解決:構建語法樹,定義終結符與非終結符。

關鍵代碼:構建環境類,包含解釋器以外的一些全局信息,通常是 HashMap。

應用實例:編譯器、運算表達式計算。

優勢: 一、可擴展性比較好,靈活。 二、增長了新的解釋表達式的方式。 三、易於實現簡單文法。

缺點: 一、可利用場景比較少。 二、對於複雜的文法比較難維護。 三、解釋器模式會引發類膨脹。 四、解釋器模式採用遞歸調用方法。

使用場景: 一、能夠將一個須要解釋執行的語言中的句子表示爲一個抽象語法樹。 二、一些重複出現的問題能夠用一種簡單的語言來進行表達。 三、一個簡單語法須要解釋的場景。

注意事項:可利用場景比較少,JAVA 中若是碰到能夠用 expression4J、FEL表達式代替。

相關文章
相關標籤/搜索