解释器模式

Author Avatar
丁起男 06月 30,2021
  • 在其它设备中阅读本文章

解释器模式

需求

四则运算

通过解释器模式来实现四则运算,如计算a+b+c的值,具体要求:

  1. 先输入表达式的形式,比如a+b+c-d+e,要求表达式不能重复
  2. 在分别输入a、b、c、d、e的值
  3. 最后求出结果

基本介绍

  • 在编译原理中,一个算术表达式通过词法分析器形成词法单元,而后这些词法单元再通过语法分析器构建语法分析树,最终形成一颗抽象的语法分析树。这里的词法分析器和语法分析器都可以看成是解释器
  • 解释器模式:是指给定一个语言(表达式),定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子(表达式)
  • 应用场景:
    • 应用可以将一个需要解释执行的语言中的句子表示为一个抽象语法树
    • 一些重复出现的问题可以用一种简单的语言来表达
    • 一个简单语法需要解释的场景

代码

抽象类表达式

//抽象类表达式,通过HashMap键值对,可以获取到变量的值
public abstract class Expression{
    //解释公式和数值
    //key就是公式(表达式)
    //value就是具体的值
    public abstract int interpreter(HashMap<String,Integer> var);
}

变量解析器

public class VarExpression extends Expression{
    
    private String key;
    
    public VarExpression(String key){
        this.key = key;
    }
    //根据变量的名称,返回对应的值
    @Override
    public int interpreter(HashMap<String,Integer> var){
        return var.get(this.key);
    }
}

符号解析器

//抽象运算符号解析器这里,每个运算符号,都只和自己左右两个数字有关系
//但左右两个数字有可能也是一个解析的结果,无论何种类型,都是Expression类的实现
public class SymbolExpression extends Expression{
    
    protected Expression left;
    protected Expression right;
    
    public SymbolExpression(Expression left,Expression right){
        this.left = left;
        this.right = right;
    }
    
    //因为SymbolExpression是让子类来实现的,因此interpreter是一个空实现
    @Override
    public int interpreter(HashMap<String,Integer> var){
        return 0;
    }
}

符号解析器实现

//加法解释器
public class AddExpression extends SymbolExpression{
    
    public AddExpression(Expression left,Expression right){
        super(left,right);
    }
    //处理加法
    @Override
    public int interpreter(HashMap<String,Integer> var){
        //super.left.interpreter(var):返回left表达式对应的值
        //super.right.interpreter(var):返回right表达式对应的值
        return super.left.interpreter(var) + super.right.interpreter(var);
    }
}
//减法解释器
public class SubExpression extends SymbolExpression{
    
    public SubExpression(Expression left,Expression right){
        super(left,right);
    }
    //处理减法
    @Override
    public int interpreter(HashMap<String,Integer> var){
        return super.left.interpreter(var) - super.right.interpreter(var);
    }
}

计算器

public class Calculator{
    //定义表达式
    private Expression expression;
    
    public Calculator(String expStr){
        //安排运算先后顺序
		Stack<Expression> stack = new Stack<>();
        //将表达式拆分成字符数组
        char[] charArray = expStr.toCharArray();
        
        Expression left = null;
        Expression right = null;
        //遍历字符数组,针对不同情况进行处理
        for(int i=0; i<charArray.length; i++){
            switch(charArray[i]){
                case '+':
                    left = stack.pop();//从stack去除左表达式
                    right = new VarExpression(String.valueOf(charArray[++i]));//创建右表达式
                    stack.push(new AddExpression(left,right));
                    break;
                case '-':
                    left = stack.pop();
                    right = new VarExpression(String.valueOf(charArray[++i]));
                    stack.push(new SubExpression(left,right));
                    break;
                default:
                    stack.push(new VarExpression(String.valueOf(charArray[++i])));
            }
        }
        //遍历完后,栈中就得到最后的Expression
        this.expression = stack.pop();
    }
    
    public int run(HashMap<String,Integer> var){
        return this.expression.interpreter(var);
    }
}

使用

//表达式
String expStr = "a+b-c";
//参数
HashMap<String,Integer> var = new HashMap();
var.put("a",1);
var.put("b",2);
var.put("c",3);
//计算
System.out.println(new Calculator(expStr).run(var));

总结

  • 当有一个语句需要解释执行,可将该语言中的句子表示为一个抽象语法树,就可以考虑使用解释器模式,让程序具有良好的扩展性
  • 应用场景:编译器、运算表达式计算、正则表达式、机器人等
  • 使用解释器可能带来的问题:解释器模式会引起类膨胀、解释器模式采用递归调用方法,将会导致调试非常复杂、效率可能降低