设计模式之解释器模式

设计模式之解释器模式

解释器模式:是一种按照规定语法进行解析的方案,在现在项目中使用较少 ,给定一门语言,定义它的规则的一种表达式,并定义一个解释器,该解释器使用该表达式来解释语言中的句子。

用的比较少,了解即可

2.解释器模式例子:

  例子:输入一个模型公式(加、减运算),然后输入模型中的参数,运算出结果。

3.代码

3.1 创建一个Expression表达式类

public abstract class Expression {

    /**
     * 抽象表达式,用来解析表达式的值
     * map的key表示具体的变量。value表示变量的值
     *
     * @param map
     * @return
     */
    public abstract int interpreter(Map<String, Integer> map);
}

3.2 创建一个变量解析器  

public class VarExpression extends Expression {

    private String key;

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

    // 获取具体变量的值
    @Override
    public int interpreter(Map<String, Integer> map) {
        return map.get(key);
    }
}

3.3 抽象运算符号解析器

public abstract class SymbolExpression extends Expression {

    protected Expression left;

    protected Expression right;

    public SymbolExpression(Expression left, Expression right) {
        System.out.println("调用了symbolExpression中的方法=========>left  " + left + "=========>" + "right:  " + right + "  ");
        this.left = left;
        this.right = right;
    }
}

3.4 加法解析器

public class AddExpression extends SymbolExpression {

    public AddExpression(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpreter(Map<String, Integer> map) {
        int result = super.left.interpreter(map) + super.right.interpreter(map);
        System.out.println("   add中的result============>" + result + "  ");
        return result;
    }
}

3.5 减法解析器

public class SubExpression extends SymbolExpression {

    public SubExpression(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpreter(Map<String, Integer> map) {
        int subresult = super.left.interpreter(map) - super.right.interpreter(map);
        System.out.println("   sub计算结果=======>" + subresult + "   ");
        return subresult;
    }
}

3.6 创建解析器封装器

public class Calculator {

    private Expression expression;

    public Calculator(String expStr) {
        // 定义一个栈,安排运行的先后执行
        Stack<Expression> stack = new Stack<>();
        // 表达式拆分为字节数据
        char[] charArray = expStr.toCharArray();

        Expression left;
        Expression right;
        for (int i = 0; i < charArray.length; i++) {
            switch (charArray[i]) {
                case '+':
                    left = stack.pop();
                    right = new VarExpression(String.valueOf(charArray[++i]));
                    stack.push(new AddExpression(left, right));
                    System.out.println("left: " + left + "  right==>" + right + "  stack中的值======>" + stack.toString());
                    break;
                case '-':
                    left = stack.pop();
                    right = new VarExpression(String.valueOf(charArray[++i]));
                    stack.push(new SubExpression(left, right));
                    System.out.println("left: " + left + "  right==>" + right + "  stack中的值======>" + stack.toString());
                    break;
                default:
                    // 公式中的变量
                    stack.push(new VarExpression(String.valueOf(charArray[i])));
                    System.out.println("stack中的值======>" + stack.toString());
            }
        }
        // 把运算结果抛出来
        this.expression = stack.pop();
    }

    // 开始运算
    public int run(HashMap<String, Integer> map) {
        return this.expression.interpreter(map);
    }
}

3.7 客户端代码

public class Client {

    public static void main(String[] args) throws Exception {
        String expStr = getExpStr();
        Calculator calculator = new Calculator(expStr);
        // 赋值
        HashMap<String, Integer> var = getVar(expStr);
        System.out.println("运算结果为:" + expStr + "=" + calculator.run(var));
    }

    private static HashMap<String, Integer> getVar(String expStr) throws Exception {

        HashMap<String, Integer> hashMap = new HashMap<String, Integer>();
        // 解析几个参数要传递
        for (char ch : expStr.toCharArray()) {
            if (ch != '+' && ch != '-') {
                // 解决重复参数的问题
                if (!hashMap.containsKey(String.valueOf(ch))) {
                    System.out.println("请输入变量" + ch + "的值: ");
                    String in = (new BufferedReader(new InputStreamReader(System.in))).readLine();
                    hashMap.put(String.valueOf(ch), Integer.valueOf(in));
                }
            }
        }
        return hashMap;
    }

    private static String getExpStr() throws IOException {
        System.out.println("请输入表达式");
        return (new BufferedReader(new InputStreamReader(System.in))).readLine();
    }
}

运行截图:

4.解释器的优点:

  解释器是一个简单语法分析工具,它最显著的优点就是扩展性,修改语法规则只要修改相应的表达式就可以了,若扩展语法,则只要增加规则类就可以了,例如add,sub。

5.解释器的缺点

  • 解释器模式会引起类膨胀:一个规则加一个类
  • 解释器模式采用递归调用方法:如果程序报错了,一步步调试下去,非常复杂
  • 效率问题:解释器模式由于使用了大量的循环和递归,效率是一个不容忽视的问题,特别是一用于解析复杂、冗长的语法时,效率是难以忍受的。

6.解释器的应用场景

  • 重复发生的问题可以使用解释器模式
  • 一个简单语法需要解释的场景

7.解释器模式注意事项

  尽量不要在重要的模块中使用解释器模式,否则维护会是一个很大的问题。在项目中可以使用shell、JRuby、Groovy等脚本语言来代替解释器模式,弥补Java编译型语言的不足。我所在公司是金融证券公司,涉及到很多业务类型的计算场景。我们的计算组件采用的时候MVEL表达式的方式进行计算,使用起来美滋滋的。准备使用解释器模式的时候,可以百度搜一下Expression4J、MESP(Math Expression String Parser)、Jep等开源的解析工具包。功能都异常强大,而且非常容易使用,效率也还不错,实现大多数的数学运算完全没有问题。总之,就是有大佬开发的现成的工具,直接拿来用就好了

原文地址:https://www.cnblogs.com/yingxiaocao/p/13523147.html