解释器模式

化简为繁的翻译机-解释器模式

模式简介

定义:给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的例子

使用场景

  1. 如果某个简单的语言需要解释执行而且可以将语言中的语句表示为一个抽象语法树时可以考虑使用解释器模式
  2. 在某些特定的领域出现不断重复的问题时,可以将该领域的问题转换为一种语法规则下的语句,然后构建解释器来解释该语句

简单实现

抽象的算术运算解释器 为所有解释器共性的提取

1
2
3
4
5
package InterpreterMode;
public abstract class ArithmeticExpression {
    //抽象的解析方法
    public abstract int interpret();
}

数字解释器 为了解释数字

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package InterpreterMode;

public class NumExpression extends ArithmeticExpression {
    private int num;

    public NumExpression(int num) {
        this.num = num;
    }

    public int interpret() {
        return num;
    }
}

运算符号抽象解释器 为所有运算符号解释器共性的提取

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package InterpreterMode;

public abstract class OperatorExpression extends ArithmeticExpression {
    protected ArithmeticExpression exp1,exp2;

    public OperatorExpression(ArithmeticExpression exp1, ArithmeticExpression exp2) {
        this.exp1 = exp1;
        this.exp2 = exp2;
    }

}

加法运算抽象解释器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
package InterpreterMode;

public class AdditionExpression extends OperatorExpression {
    public AdditionExpression(ArithmeticExpression exp1, ArithmeticExpression exp2) {
        super(exp1, exp2);
    }
    public int interpret() {
        return exp1.interpret()+exp2.interpret();
    }
}

处理与解释相关的一些业务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package InterpreterMode;

import java.util.Stack;

public class Calculator {
    //声明一个Strack栈
    private Stack<ArithmeticExpression> stack=new Stack<ArithmeticExpression>();

    public Calculator(String express) {
        //声明2个变量,临时存储运算符左右两边的数字解释器
        ArithmeticExpression expression1,expression2;
        //根据空格分割字符串
        String[] args=express.split(" ");
        //循环数组
        for (int i = 0; i <args.length ; i++) {
            switch (args[i].charAt(0)){
                case '+'://如果是+号
                    expression1=stack.pop();
                    expression2=new NumExpression(Integer.valueOf(args[++i]));
                    stack.push(new AdditionExpression(expression1,expression2));
                    break;
                default: //如果为数字
                    stack.push(new NumExpression(Integer.valueOf(args[i])));
                    break;
            }
        }
    }

    public int calculate(){
        return stack.pop().interpret();
    }
}

测试类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
package InterpreterMode;

import StrategyMode.CalculateStrategy;

public class Client {
    public static void main(String[] args) {
        Calculator calculator=new Calculator("11 + 22 + 22 + 33");
        System.out.println(calculator.calculate());
    }
}

执行结果

jshiqi.png

总结

优点:

灵活的拓展性,当我们相对文法规则进行拓展延伸时,只需要增加相应的非终结符解释器,并在构建抽象语法树时,使用到新增的解释器对象进行具体的解释即可,非常方便

缺点:

因为对于每一条文法都可以对应至少一个解释器,其会生成大量的类,导致后期维护困难;同时,对于过于复杂的文法,构建其抽象语法树会显得异常繁琐,甚至有可能会出现需要构建多棵抽象语法树的情况,因此,对于复杂的文法并不推荐解释器模式