MENU

《Java设计模式及实践》第三章读书笔记 解释器模式

May 15, 2022 • 《Java设计模式及实践》

解释器模式

介绍

意图:给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。

主要解决:对于一些固定文法构建一个解释句子的解释器。

何时使用:如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。

优点:

  1. 可扩展性比较好,灵活。
  2. 增加了新的解释表达式的方式。
  3. 易于实现简单文法。

缺点:

  1. 可利用场景比较少。
  2. 对于复杂的文法比较难维护。
  3. 解释器模式会引起类膨胀。
  4. 解释器模式采用递归调用方法。

使用场景:

  1. 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
  2. 一些重复出现的问题可以用一种简单的语言来进行表达。
  3. 一个简单语法需要解释的场景。

注意事项:可利用场景比较少,JAVA 中如果碰到可以用 expression4J 代替。

实现

UML图

image-20200129164111914

代码

public interface Expression {
    float interpret();
}
public class Number implements Expression {
    private float number;

    public Number(float number) {
        this.number = number;
    }

    @Override
    public float interpret() {
        return number;
    }
}
/////////////////////////////////////////////
/**
 * 加法规则
 */
public class Plus implements Expression {
    Expression left, right;

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

    @Override
    public float interpret() {
        return left.interpret() + right.interpret();
    }
}
/////////////////////////////////////////////
/**
 * 减法规则
 */
public class Minus implements Expression {
    Expression left, right;

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

    @Override
    public float interpret() {
        return left.interpret() - right.interpret();
    }
}
//用于处理表达式的处理器
public class Evaluator {
    public float evaluate(String exp){
        Stack<Expression> stack = new Stack<>();
        float result = 0;
        for (String token : exp.split(" ")){
            if(isOperator(token)){
                Expression expression = null;
                if(token.equals("+"))
                    expression = stack.push(new Plus(stack.pop(), stack.pop()));
                else if(token.equals("-"))
                    expression = stack.push(new Minus(stack.pop(), stack.pop()));
                if(exp != null){
                    result = expression.interpret();
                    stack.push(new Number(result));
                }
            }
            if(isNumber(token)){
                stack.push(new Number(Float.parseFloat(token)));
            }
        }
        return result;
    }

    private boolean isNumber(String token){
        try{
            Float.parseFloat(token);
            return true;
        }catch (NumberFormatException e){
            return false;
        }
    }

    private boolean isOperator(String token){
        return token.equals("+") || token.equals("-");
    }
}
public class Main {
    public static void main(String[] args) {
        Evaluator evaluator = new Evaluator();
        //逆波兰表示法
        System.out.println(evaluator.evaluate("1 2 +"));        //1+2
        System.out.println(evaluator.evaluate("5 2 -"));        //2-5
        System.out.println(evaluator.evaluate("4 8 - 2 +"));    //8-4+2
    }
}
Github

interpreter