天天看點

設計模式(十六) 解釋器模式

解釋器模式是一種行為型模式,它的主要作用是用一種方式來實作對表達式或文法的處理。我們可以使用解釋器模式處理語言的解析,在設計計算機語言的時候解釋器模式很有用處。

解釋器模式可能需要用到一點編譯原理的知識。不過我自己編譯原理的内容都忘光了,是以這裡不做編譯原理的任何介紹了。直接來看代碼吧。我們來做一個不含括号的四則運算的解釋器。

解釋器模式首先需要一個表達式接口,其中有一個方法用于解析表達式的值。

public interface Expression {
    int interpret(Context context);
}

           

之後來考慮一些具體的表達式。首先是常量表達式,這個很簡單,直接傳回常量的值即可。

class Constant implements Expression {
    private int i;

    public Constant(int i) {
        this.i = i;
    }

    @Override
    public int interpret(Context context) {
        return i;
    }
}
           

然後是變量,變量的值儲存在上下文中,在編譯領域也可以叫做符号表之類的,反正都是一個意思。

class Variable implements Expression {
    @Override
    public int interpret(Context context) {
        return context.getValue(this);
    }
}
           

上下文,或者叫符号表,是儲存變量值的地方。我們在Java中可以簡單的使用Map來當做符号表。

public class Context {
    private HashMap<Variable, Integer> map = new HashMap<>();

    public void putValue(Variable name, int value) {
        map.put(name, value);
    }

    public int getValue(Variable name) {
        return map.get(name);
    }
}
           

然後是加減乘除四種表達式。這個非常簡單,沒啥說的吧。

class Add implements Expression {
    private Expression a, b;

    public Add(Expression a, Expression b) {
        this.a = a;
        this.b = b;
    }

    @Override
    public int interpret(Context context) {
        return a.interpret(context) + b.interpret(context);
    }
}

class Sub implements Expression {
    private Expression a, b;

    public Sub(Expression a, Expression b) {
        this.a = a;
        this.b = b;
    }

    @Override
    public int interpret(Context context) {
        return a.interpret(context) - b.interpret(context);
    }
}

class Mul implements Expression {
    private Expression a, b;

    public Mul(Expression a, Expression b) {
        this.a = a;
        this.b = b;
    }

    @Override
    public int interpret(Context context) {
        return a.interpret(context) * b.interpret(context);
    }
}

class Div implements Expression {
    private Expression a, b;

    public Div(Expression a, Expression b) {
        this.a = a;
        this.b = b;
    }

    @Override
    public int interpret(Context context) {
        return a.interpret(context) / b.interpret(context);
    }
}
           

這些類都準備好之後,我們就可以測試一下解釋器模式了。我們手動建立一個表達式,然後調用它的

interpret()

方法對其求值。之後,表達式就會如我們所願的給出結果。

public void run() {
        Variable a = new Variable();
        Variable b = new Variable();
        Context context = new Context();
        context.putValue(a, 3);
        context.putValue(b, 4);

        //a+b*(a-b)+2
        Expression expression = new Add(a, new Add(new Mul(b, new Sub(a, b)), new Constant(2)));
        System.out.println("a+b*(a-b)+2=" + expression.interpret(context));
    }
           

當然,這隻是一個非常簡單的小例子,因為

new Add(a, new Add(new Mul(b, new Sub(a, b)), new Constant(2)))

這個表達式樹是我們手動建立的。如果我們希望更加實用的話,就需要自己編寫程式,解析字元串,然後轉換為抽象文法樹。這就屬于編譯原理的話題了。

參考資料:

設計模式(行為型)之解釋器模式(Interpreter Pattern)