17、解释器模式(Interpreter Pattern)

2020-08-23  本文已影响0人  火山_6c7b

1. 解释器模式

1.1 简介

  Interpreter(解释器)模式是对特定的计算机程序设计语言,用来解释预先定义的文法。Interpreter模式是一种简单的语法解释器,属于行为模式。给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

  编译原理上的编译器分为词法分析器、语法分析器、语义分析器、中间代码优化器以及最终的最终代码生成器几个部分。而这个解释器其实就是完成了对语法的解析,将一个个的词组解释成了一个个语法范畴,之后拿来使用。Interpreter模式的目的就是使用一个解释器为用户提供一个一门定义语言的语法表示的解释器,然后通过这个解释器来解释语言中的句子。提供了一个实现语法解释器的框架。

  Interpreter(解释器)模式大多用来解释一些(自定义的)独特语法,例如某些游戏开发引擎中读取XML文件,或是WindowsPhone开发中的XAML文件,都是使用此模式来进行的。与其说是一种模式,不如说是一种具有通用规范的行为更为准确。

1.2 结构

Interpreter 模式uml:

Interpreter 模式uml.png

Interpreter 模式角色:

2. Interpreter 模式示例

  Interpreter 模式的示例代码很简单, 只是为了说明模式的组织和使用, 实际的解释Interpret 逻辑没有实际提供。

  Interpreter模式和Composite模式相似,最终将构造为一颗语法树。以算术表达式"20(3+1)-45+3"为例,用Interpreter 模式写一个计算表达式的示例。

Interpreter接口:

public interface Interpreter {
    double calculate(String expression);
}

终态Interpreter:

public class Number implements Interpreter {

    private double number;

    public Number(double number) {
        super();
        this.number = number;
    }

    @Override
    public double calculate(String expression) {
        return number;
    }

}

非终态加法Interpreter:

public class Add implements Interpreter {

    private Interpreter left;

    private Interpreter right;

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

    @Override
    public double calculate(String expression) {
        return left.calculate(expression) + right.calculate(expression);
    }

}

解释器ParserInterpreter(解析算术表达式,构造语法树):

public class ParserInterpreter implements Interpreter {

    @Override
    public double calculate(String expression) { //1 * (2 + 3)
        StringBuilder number = new StringBuilder();
        LinkedList<Interpreter> interpreters = new LinkedList<>();
        LinkedList<Character> operators = new LinkedList<>();
        for (char ch : expression.toCharArray()) {
            if (isOperator(ch)) {
                //将之前的数字入栈
                if (number.length() > 0) {
                    interpreters.add(new Number(Double.parseDouble(number.toString())));
                    number.setLength(0);
                }
                //组装表达式
                while (interpreters.size() >= 2) {
                    Character lastOp = operators.getLast();
                    //碰到左括号
                    if (isOpenParen(lastOp)) {
                        break;
                    }
                    //碰到了运算符,但下一个运算符优先级是否更高?
                    if (rightOperatorGreater(lastOp, ch)) {
                        break;
                    }
                    Interpreter right = interpreters.removeLast();
                    Interpreter left = interpreters.removeLast();
                    Interpreter interpreter = constructExpression(left, 
                            operators.removeLast(), right);
                    interpreters.addLast(interpreter);
                }
                if (isCloseParen(ch)) {
                    //碰到右括号,直接去掉左括号
                    operators.removeLast();
                } else {
                    //非右括号,直接进栈
                    operators.addLast(ch);
                }
            } else {
                number.append(ch);
            }
        }
        //最后是数字,如1*2+3
        if (number.length() > 0) {
            interpreters.add(new Number(Double.parseDouble(number.toString())));
            number.setLength(0);
        }
        //最后一次运算
        if (operators.size() > 0) {
            Interpreter right = interpreters.removeLast();
            Interpreter left = interpreters.removeLast();
            Interpreter interpreter = constructExpression(left, 
                    operators.removeLast(), right);
            interpreters.addLast(interpreter);
        }
        //调用组装好的树
        return interpreters.pop().calculate(expression);
    }
    
    /**
     * 右边运算符是否优先级更高
     */
    private boolean rightOperatorGreater(char leftOp, char rightOp) {
        if (rightOp == '*' || rightOp == '/') {
            return leftOp == '+' || leftOp == '-';
        }
        return false;
    }
    
    private boolean isOperator(char ch) {
        return ch == '-' || ch == '+' || ch == '/' || ch == '*' || ch == '(' || ch ==')';
    }
    
    private boolean isOpenParen(char ch) {
        return ch == '(';
    }
    
    private boolean isCloseParen(char ch) {
        return ch == ')';
    }
    
    private Interpreter constructExpression(Interpreter left, char op, Interpreter right) {
        switch (op) {
        case '+' :
            return new Add(left, right);
        case '-' :
            return new Sub(left, right);
        case '*' :
            return new Plus(left, right);
        case '/' :
            return new Divide(left, right);
        default:
            break;
        }
        return null;
    }

}

调用示例:

    public static void main(String[] args) {
        ParserInterpreter interpreter = new ParserInterpreter();
        double result = interpreter.calculate("20*(3+1)-4*5+3");
        System.out.println("计算结果为: " + result);
    }

3. 总结

Interpreter 模式优点:

Interpreter 模式缺点:

上一篇 下一篇

猜你喜欢

热点阅读