zoukankan      html  css  js  c++  java
  • 设计模式之解释器模式

    设计模式之解释器模式

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

    用的比较少,了解即可

    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
Copyright © 2011-2022 走看看