每天一个设计模式之(20)-----解释器模式

1.为什么要使用解释器模式

    解释器模式的应用场景为,当一个系统的需要运算的公式过多时,要为每一个公式实现一个接口,那么接口数量必然暴增,但是使用解释器模式的话,可以让代码去解释每一个公式,并实现自动计算,这样,我们就不需要为每一个公式进行开发接口。有点类似于人工智能的感觉。学习这个模式的时候,让我想起了一门课程,叫编译原理。回想此课程,令人痛不欲生。因为其语法树解析的概念,正是解释器模式的核心概念。

2.先看类图

    以加减运算为例子。比如说我的系统有A+B的公式,也有A-B的公式,还有A+B-C的公式,还有其它公式,通常来说,我们会为每一种公式开发一个接口,根据业务逻辑去选择哪个接口调用,这种方式在公式少的时候可以去进行使用,但是公式一旦多起来,就很麻烦。但是解释器模式不同,你只要把公式给我,并把A,B,C的值给我,那么我就可以帮你计算出来结果。上面所说的Calculator相当于一个解释器,我们要把公式给它。Expression就相当于一个表达式,其中有VarExpression,表示值表达式(在性质上来说是终结符表达式),就是ABC;SymbolExpression是运算符表达式(在性质上说是非终结符表达式),Add,Sub就是它的具体实现,来看代码。

3.实现

    Expression相关类

/**
 * 抽象表达式
 */
public abstract class Expression {

    //解析公式和数值,其中var中的key值是公式中的参数,value值是具体的数字
    //这里的HashMap是用来存放表达式中的数值
    //比如 A + B,那么这么Map里面就是放 put(“A”,10) put(“B”,20)
    public abstract int interpreter(HashMap<String,Integer> var);

}


/**
 * 数值表达式
 */
public class VarExpression extends Expression{

    //表达式的Key,比如A,B
    private String key;

    public VarExpression(String key) {
        this.key = key;
    }

    @Override
    public int interpreter(HashMap<String, Integer> var) {
        return var.get(this.key);
    }
}


/**
 * 运算符表达式
 */
public abstract class SymbolExpression extends Expression{

    /**
     * 二叉树结构
     * 因为一个运算符两边肯定都是数值表达式
     */
    protected Expression left;
    protected Expression right;

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


/**
 * 加法表达式
 */
public class AddExpression extends SymbolExpression{

    public AddExpression(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 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);
    }
}

    Calculator类

/**
 * 解释器
 */
public class Calculator {

    /**
     * 该成员变量只是保存运算结果
     */
    private Expression expression;

    public Calculator(String expStr) {

        /**
         * 利用栈的结构
         */
        Stack<Expression> stack = new Stack<>();
        char[] chars = expStr.toCharArray();
        Expression left = null;
        Expression right = null;

        for (int i=0; i<chars.length; i++){
            switch (chars[i]) {
                case '+':
                    //如果是 + ,则构造新的表达式 A+B,并且++i,跳过下一个数字的循环
                    left = stack.pop();//取得+号左边的数字
                    right = new VarExpression(String.valueOf(chars[++i]));//取得+号右边的数字,并把下标+1,跳过下一次循环
                    stack.push(new AddExpression(left, right));//构造出新的 left+right 表达式,并入栈
                    break;
                case '-':
                    left = stack.pop();
                    right = new VarExpression(String.valueOf(chars[++i]));
                    stack.push(new SubExpression(left, right));
                    break;
                default:
                    stack.push(new VarExpression(String.valueOf(chars[i])));
            }
        }
        //运算结果
        this.expression = stack.pop();
    }

    public int run(HashMap<String,Integer> var){
        //执行递归解析
        return this.expression.interpreter(var);
    }
}

    main方法

public class Main {

    public static void main(String[] args) {
        String expStr = "a+b-a+c";
        HashMap<String, Integer> values = new HashMap<>();
        values.put("a", 10);
        values.put("b", 20);
        values.put("c", 30);

        Calculator calculator = new Calculator(expStr);
        int run = calculator.run(values);

        //显示结果
        for (Character c : expStr.toCharArray()){
            System.out.print(values.containsKey(c.toString()) ? values.get(c.toString()) : c.toString());
        }
        System.out.println(" = " +run);
    }
}

//输出结果
10+20-10+30 = 50

4.总结

    以上就是解释器模式。实现起来非常的麻烦。而且是只有加减的情况下,但是使用起来非常简单。如果在此基础上再加上乘除,那么判断就不是这么简单了,还要考虑计算的优先级。可见一个想要实现编译器的语法解析树得有多复杂。不过幸运的是,现在第三方已经提供了一些关于运算的解释器模式,Expression4J、MESP(Math Expression String Parser)、Jep等。大家可以自行使用

转载于:https://my.oschina.net/u/3582320/blog/1490281

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值