設計模式--解釋器模式

Java工程源碼

類圖

這裏寫圖片描述


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


優點
- 擴展性好,修改語法規則只要修改相應的非終結符表達式就可以了

缺點
- 容易引起類膨脹。每個語法都要產生一個非終結符表達式
- 採用遞歸方法,不易調試
- 效率問題。大量使用了循環和遞歸


注意事項
解釋器模式一般用來解析比較標準的字符集,如SQL語法分析等


抽象表達式

public abstract class AbstractExpression {
    public abstract Object interpret(Context ctx);

    /**
     * 檢驗兩個表達式在結構上是否相同
     *
     * @param exp 表達式
     * @return 是否相同
     */
    public abstract boolean equals(AbstractExpression exp);
}

終結符表達式

public abstract class TerminalExpression extends AbstractExpression {
}

非終結符表達式

public abstract class NonterminalExpression extends AbstractExpression {
    /**
     * 校驗表達式結果是否是Boolean類型
     *
     * @param result 表達式結果
     * @param expStr 表達式
     * @throws IllegalArgumentException
     */
    public void checkBoolean(Object result, String expStr) throws IllegalArgumentException {
        if (!(result instanceof Boolean)) {
            throw new IllegalArgumentException("表達式" + expStr + "參數類型錯誤,參數類型應爲:Boolean");
        }
    }
    /**
     * 校驗表達式結果是否是Integer類型
     *
     * @param result 表達式結果
     * @param expStr 表達式
     * @throws IllegalArgumentException
     */
    public void checkInteger(Object result, String expStr) throws IllegalArgumentException {
        if (!(result instanceof Integer)) {
            throw new IllegalArgumentException("表達式" + expStr + "參數類型錯誤,參數類型應爲:Integer");
        }
    }
}

變量終結符

public class Variable extends TerminalExpression {
    private String name;

    /**
     * 變量
     *
     * @param name 變量名
     */
    public Variable(String name) {
        this.name = name;
    }

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

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


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

整型終結符

public class MyInt extends TerminalExpression {
    private final int value;

    public MyInt(int value) {
        this.value = value;
    }

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

    @Override
    public boolean equals(AbstractExpression exp) {
        if (exp != null && exp instanceof MyInt) {
            return this.value == ((MyInt) exp).value;
        }
        return false;
    }

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

布爾型終結符

public class MyBoolean extends TerminalExpression {
    public static final MyBoolean TRUE = new MyBoolean(true);
    public static final MyBoolean FALSE = new MyBoolean(false);
    private final boolean value;

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

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

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


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

上下文

public class Context {
    /**
     * 變量存儲區
     */
    private Map<Variable, TerminalExpression> map = new HashMap<>();

    /**
     * 變量賦值
     *
     * @param var   變量
     * @param value 值
     */
    public void assign(Variable var, TerminalExpression value) {
        map.put(var, value);
    }

    /**
     * 查看變量內容
     *
     * @param var 變量
     * @return 變量值
     * @throws IllegalArgumentException
     */
    public Object lookup(Variable var) throws IllegalArgumentException {
        TerminalExpression value = map.get(var);
        if (value == null) {
            throw new IllegalArgumentException();
        }
        return value.interpret(this);
    }
}

加運算表達式

public class Add extends NonterminalExpression {
    private final AbstractExpression left, right;

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

    @Override
    public Object interpret(Context ctx) {
        Object leftObj = left.interpret(ctx);
        Object rightObj = right.interpret(ctx);
        //參數檢查
        checkInteger(leftObj, left.toString());
        checkInteger(rightObj, right.toString());
        return (Integer) leftObj + (Integer) rightObj;
    }

    @Override
    public boolean equals(AbstractExpression exp) {
        if (exp != null && exp instanceof Add) {
            return left.equals(((Add) exp).left) &&
                    right.equals(((Add) exp).right);
        }
        return false;
    }

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

乘運算表達式

public class Multiply extends NonterminalExpression {
    private final AbstractExpression left, right;

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

    @Override
    public Object interpret(Context ctx) {
        Object leftObj = left.interpret(ctx);
        Object rightObj = right.interpret(ctx);
        //參數檢查
        checkInteger(leftObj,left.toString());
        checkInteger(rightObj,right.toString());
        return (Integer) leftObj * (Integer) rightObj;
    }

    @Override
    public boolean equals(AbstractExpression exp) {
        if (exp != null && exp instanceof Multiply) {
            return left.equals(((Multiply) exp).left) &&
                    right.equals(((Multiply) exp).right);
        }
        return false;
    }

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

與運算表達式

public class And extends NonterminalExpression {
    private final AbstractExpression left, right;

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

    @Override
    public Object interpret(Context ctx) {
        Object leftObj = left.interpret(ctx);
        Object rightObj = right.interpret(ctx);
        //參數檢查
        checkBoolean(leftObj, left.toString());
        checkBoolean(rightObj, right.toString());
        return (Boolean) leftObj && (Boolean) rightObj;
    }

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

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

或運算表達式

public class Or extends NonterminalExpression {
    private AbstractExpression left, right;

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

    @Override
    public Object interpret(Context ctx) {
        Object leftObj = left.interpret(ctx);
        Object rightObj = right.interpret(ctx);
        //參數檢查
        checkBoolean(leftObj, left.toString());
        checkBoolean(rightObj, right.toString());
        return (Boolean) leftObj || (Boolean) rightObj;
    }

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

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

非運算表達式

public class Not extends NonterminalExpression {
    private AbstractExpression exp;

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

    @Override
    public Object interpret(Context ctx) {
        Object expObj = exp.interpret(ctx);
        //參數檢查
        checkBoolean(expObj, exp.toString());
        return !(Boolean) exp.interpret(ctx);
    }

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

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

場景類

public class Client {
    public static void main(String[] args) {
        Context ctx = new Context();
        // 變量x
        Variable x = new Variable("x");
        // 變量y
        Variable y = new Variable("y");
        // 變量z
        Variable z = new Variable("z");
        // 變量賦值
        ctx.assign(x, MyBoolean.FALSE);
        ctx.assign(y, MyBoolean.TRUE);
        ctx.assign(z, new MyInt(5));
        System.out.println("x=" + x.interpret(ctx));
        System.out.println("y=" + y.interpret(ctx));
        System.out.println("z=" + z.interpret(ctx));
        // 表達式(true AND x)
        AbstractExpression exp1 = new And(MyBoolean.TRUE, x);
        System.out.println(exp1.toString() + "=" + exp1.interpret(ctx));
        // 表達式((true AND x) OR (y AND (NOT x)))
        AbstractExpression exp2 = new Or(new And(MyBoolean.TRUE, x), new And(y, new Not(x)));
        System.out.println(exp2.toString() + "=" + exp2.interpret(ctx));
        // 表達式((z + 3) + 2)
        AbstractExpression exp3 = new Add(new Add(z, new MyInt(3)), new MyInt(2));
        System.out.println(exp3.toString() + "=" + exp3.interpret(ctx));
        // 表達式(2 + (z * 3))
        AbstractExpression exp4 = new Add(new MyInt(2), new Multiply(z, new MyInt(3)));
        System.out.println(exp4.toString() + "=" + exp4.interpret(ctx));

        System.out.println("表達式1,2是否是同一個表達式:" + exp1.equals(exp2));
    }
}

運行結果

x=false
y=true
z=5
(true AND x)=false
((true AND x) OR (y AND (NOT x)))=true
((z + 3) + 2)=10
(2 + (z * 3))=17
表達式1,2是否是同一個表達式:false
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章