zoukankan      html  css  js  c++  java
  • 面向对象的设计模式(十三),解释器模式

    解释器模式,从字面上解释来说就是为一个文法(具有特定语法的形式的语句或表达式)构造解释器,这个解释器用来解释这个文法,使得这样的具有某种书写规则的文法能够表示特定的功能,这样的特定书写规则也就是通常所说的语法,如C/C++,Java,Python等计算机语言有自己的语法。还有,一些解释型语言如Python。它在执行的时候须要Python解释器,这也就是一种解释器。

    定义:解释器模式为一些具有特定书写规则的文法编写解释器,从而使得它具有某种意义。

    使用场景:

    1. 作为解释器

      解释具有特定语法的语句的功能或者意义。如解释具有特定书写规则的语句,在以下的这个样例中就是作为解释器来解释运算表达式。

    2. 作为翻译机或者译码器。如高级语言中的常量,编译的时候编译器系统会将常量替换成它代表的数一样,相似的我们也能够定义一些特定的具有某种意义的语句。然后用对应的解释器来解释器它。

    假设又这么个表达式或语句a_+_b_-_c,我们想要知道它的意思,假如我们规定_符号用来分隔数字和运算符,那么上面的这个语句表达的意思就是计算a+b-c。这和学生考试的时候。它们规定1表示A,2表示B,3表示C,4表示D来传选择题答案一样的,相似于编码译码过程。事实上译码器也就是解释器,那么我们通过代码来解释上面表达式的意思。

    代码实现:

    抽象解释器(基类)

    /**
     * 主要的解释器。是全部解释器的基类
     * @author lt
     *
     */
    public abstract class BaseInterpreter<T> {
    
        /**
         * 抽象解释方法
         * @return
         */
        public abstract T interpret();
    }

    抽取了解释器的共性

    整数解释器(解释整数)

    /**
     * 整数解释器
     * @author lt
     *
     */
    public class NumberInterpreter extends BaseInterpreter<Integer>{
    
        private int num;
    
        public NumberInterpreter(int num){
            this.num = num;
        }
    
        @Override
        public Integer interpret() {
            return this.num; // 自己主动装箱拆箱
        }
    }

    解释整数,直接返回这个整数。这里的整数也就是终结符

    运算符解释器(基类

    /**
     * 二目运算符操作解释器,也是一个基类,由于有好多的二目运算符
     * @author lt
     *
     */
    public abstract class OperatorInterpreter extends BaseInterpreter<Integer>{
    
        protected BaseInterpreter<Integer> exp1;
        protected BaseInterpreter<Integer> exp2;
    
        public OperatorInterpreter(BaseInterpreter<Integer> exp1,BaseInterpreter<Integer> exp2){
            this.exp1 = exp1;
            this.exp2 = exp2;
        }
    
    }

    解释二目运算符。须要两个整数,为非终结符解释器。

    加法解释器(计算加法)

    /**
     * 加法解释器。计算加法
     * @author lt
     *
     */
    public class AdditionInterpreter extends OperatorInterpreter{
    
        public AdditionInterpreter(BaseInterpreter<Integer> exp1,
                BaseInterpreter<Integer> exp2) {
            super(exp1, exp2);
        }
    
        /**
         * 用来计算加法
         */
        @Override
        public Integer interpret() {
            return exp1.interpret() + exp2.interpret();
        }
    }

    减法解释器(计算减法)

    /**
     * 减法计算器
     * @author lt
     *
     */
    public class SubtractionInterpreter extends OperatorInterpreter{
    
        public SubtractionInterpreter(BaseInterpreter<Integer> exp1,
                BaseInterpreter<Integer> exp2) {
            super(exp1, exp2);
        }
    
        @Override
        public Integer interpret() {
            return exp1.interpret() - exp2.interpret();
        }
    }

    计算器,翻译a_+_b_-_c(计算表达式)

    import java.util.Stack;
    
    /**
     * 计算器
     * @author lt
     *
     */
    public class Calculator {
    
        private Stack<BaseInterpreter<Integer>> mExpStack = new Stack<BaseInterpreter<Integer>>();
    
        public Calculator(String expression){
            // 声明两个BaseInterpreter<Integer>的暂时变量,由于计算必须要记录两个数
            BaseInterpreter<Integer> exp1,exp2;
    
            //  以符号_分隔,这是我们自己规定的
            String[] exps = expression.split("_");
    
            for(int i=0;i<exps.length;i++){
                switch (exps[i].charAt(0)) {
                case '+': // 加法
                    exp1 = mExpStack.pop();
                    exp2 = new NumberInterpreter(Integer.valueOf(exps[++i]));
                    mExpStack.push(new AdditionInterpreter(exp1, exp2));
                    break;
                case '-':
                    exp1 = mExpStack.pop();
                    exp2 = new NumberInterpreter(Integer.valueOf(exps[++i]));
                    mExpStack.push(new SubtractionInterpreter(exp1, exp2));
                    break;
                default: // 数字
                    mExpStack.push(new NumberInterpreter(Integer.valueOf(exps[i])));
                    break;
                }
            }
        }
    
        /**
         * 计算
         * @return
         */
        public int calculate(){
            return mExpStack.pop().interpret();
        }
    }

    这个类用来翻译a_+_b_-_c等形式结构的语句的意思。这里的符号_是我规定用来分隔数字的,当然你也能够规定其它符号作为分隔符。

    这个类的方法也非常easy,构造方法中先是将表达式按符号_分隔。得到一些运算符和数字,然后在依据分隔出来的字符串的第一个字符的类型推断是+运算符还是-运算符还是数字,假设是+运算符。那么就将存储的上一个数字弹出栈并记录到exp1,然后得到运算符后面的那个字符串(肯定是数字)并记录到变量exp2中。最后用加法解释器解释这两个变量记录的数字并压入栈,等下一次循环的时候弹出和下一个数字进行计算;假设是-运算符,那么和+运算符是一样的,仅仅只是用的是减法解释器;假设是数字,直接压入栈,整个过程是逐步计算的过程。calculate方法用来输出计算结果。

    測试

    public class Test {
    
        public static void main(String[] args) {
            String testStr = "1_+_34_-_10_+_50";
            Calculator calculator = new Calculator(testStr);
            System.out.println("result="+calculator.calculate());
        }
    }

    结果:

    这里写图片描写叙述

     能够看到我们定义的解释器成功解释了a_+_b_-_c这样的形式的语句,事实上这个解释器实现的功能相似译码的功能或者翻译的功能。只是话说回来,尽管是成功解释了那种形式的语句,可是也仅仅能计算整数的加减法。假设想要做其它运算或者其它类型的数字,如乘除法和浮点型,那么须要加入对应的解释器,但假设涉及到混合运算的时候,那复杂多了,还得考虑优先级。这个时候这样的模式可能就不适合了,也就是说解释器模式适合于简单的语句。

    总结

    长处:

    • 灵活的扩展性

      当我们对语法规则扩展延伸适合,仅仅须要加入对应的非终结符解释器(如上面的加减法解释器),并在构建抽象语法树时,使用到新添加的解释器对象(如加入减法解释器)进行详细的解释(计算减法)就可以,非常方便。非终结符也就是还没有结束的符号,如以下样例中的加法和减法解释器分别解释的加好和减号一样,它们是二目运算符。其两边肯定要两个数。

    缺点:

    • 类数量膨胀,后期维护困难。由于对于每一条文法都对应至少一个解释器类,会产生大量的类,导致后期维护困难。同一时候,对于复杂的文法,构建其抽象的语法树会显得比較繁琐,甚至须要构建多颗语法树,因此。对于复杂的文法并不推荐使用解释器模式。
  • 相关阅读:
    链表_单链表(插入删除查询)
    OceanBase架构浅析(一)
    电商商品搜索现状
    ASP.NET MVC 源码分析(二) —— 从 IRouteBuilder认识路由构建
    ASP.NET MVC 源码分析(一)
    RPC框架分析
    RPC简介
    Performance Metrics(性能指标2)
    Performance Metrics(性能指标1)
    Introduction(本书简介)
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/8905653.html
Copyright © 2011-2022 走看看