zoukankan      html  css  js  c++  java
  • 设计模式解密(21)- 解释器模式

    1、简介

    定义:给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。

    主要解决:对于一些固定文法构建一个解释句子的解释器。

    本质:分离实现,解释执行。Interpreter模式其实就是一种简单的语法解释器构架。

    英文:Interpreter

    类型:行为型

    2、类图及组成

    (引)类图:


    组成:
      AbstractExpression(抽象表达式):定义解释器的接口,约定解释器的解释操作。

      TerminalExpression(终结符表达式):用来实现语法规则中和终结符相关的操作,不再包含其它的解释器,如果用组合模式来构建抽象语法树的话,就相当于组合模式中的叶子对象,可以有多种终结符解释器。

      NonterminalExpression(非终结符表达式):用来实现语法规则中非终结符相关的操作,通常一个解释器对应一个语法规则,可以包含其它的解释器,如果用组合模式来构建抽象语法树的话,就相当于组合模式中的组合对象,可以有多种非终结符解释器。

      Context(上下文):它包含了解释器之外一些其他的全局信息;通常包含各个解释器需要的数据,或是公共的功能。

      Client(客户端):指的是使用解释器的客户端,通常在这里去把按照语言的语法做的表达式,转换成为使用解释器对象描述的抽象语法树,然后调用解释操作。

    代码结构:

    /**
     * 抽象表达式
     */
    public abstract class AbstractExpression {
        /**
         * 解释的操作
         * @param ctx 上下文对象
         */
        public abstract void interpret(Context ctx);
    }
    
    /**
     * 终结符表达式
     */
    public class TerminalExpression extends AbstractExpression{
        public void interpret(Context ctx) {
            //实现与语法规则中的终结符相关联的解释操作
        }
    }
    
    /**
     * 非终结符表达式
     */
    public class NonterminalExpression extends AbstractExpression{
        public void interpret(Context ctx) {
            //实现与语法规则中的非终结符相关联的解释操作
        }
    }
    
    /**
     * 上下文,包含解释器之外的一些全局信息
     */
    public class Context {
    
    }
    
    /**
     * 使用解释器的客户
     */
    public class Client {
        //主要按照语法规则对特定的句子构建抽象语法树
        //然后调用解释操作
    }

    3、实例引入

    场景: 与(and)、或(or)、非(not) 的一套解析器

    抽象表达式:

    package com.designpattern.Interpreter;
    
    /**
     *  抽象表达式 -- BooleanExp
     *  定义:
     *      BooleanExp -->> VariableExp | Constant | OrExp | AndExp | NotExp | '(' BooleanExp ')'
     *      AndExp -->> BooleanExp 'and' BooleanExp
     *      OrExp -->> BooleanExp 'or' BooleanExp
     *      NotExp -->> BooleanExp 'not' BooleanExp
     *      Constant -->> 'true' | 'false'
     *      VariableExp -->> 'A' | 'B' | ... | 'Z'
     *      
     * @author Json<<json1990@foxmail.com>>
     */
    public interface BooleanExp {
        
        public abstract boolean Evaluate(Context c);
        
        public abstract BooleanExp Replace(String var, BooleanExp exp);
        
        public abstract BooleanExp Copy();
    }

    3个具体表达式:

    package com.designpattern.Interpreter;
    
    /**
     * 非终结符表达式 -- and
     * @author Json<<json1990@foxmail.com>>
     */
    public class AndExp implements BooleanExp {
        private BooleanExp operand1;
        private BooleanExp operand2;
        
        public AndExp(BooleanExp oper1, BooleanExp oper2) {
            operand1 = oper1;
            operand2 = oper2;
        }
    
        public boolean Evaluate(Context c) {
            return operand1.Evaluate(c) && operand2.Evaluate(c);
        }
    
        public BooleanExp Copy() {
            return new AndExp(operand1.Copy(), operand2.Copy());
        }
    
        public BooleanExp Replace(String var, BooleanExp exp) {
            return new AndExp(operand1.Replace(var, exp),operand2.Replace(var, exp));
        }
    }
    package com.designpattern.Interpreter;
    
    /**
     * 非终结符表达式 -- or
     * @author Json<<json1990@foxmail.com>>
     */
    public class OrExp implements BooleanExp {
        private BooleanExp operor1;
        private BooleanExp operor2;
        
        public OrExp(BooleanExp oper1, BooleanExp oper2) {
            operor1 = oper1;
            operor2 = oper2;
        }
    
        public boolean Evaluate(Context c) {
            return operor1.Evaluate(c) || operor2.Evaluate(c);
        }
    
        public BooleanExp Copy() {
            return new OrExp(operor1.Copy(), operor2.Copy());
        }
    
        public BooleanExp Replace(String var, BooleanExp exp) {
            return new OrExp(operor1.Replace(var, exp),operor2.Replace(var, exp));
        }
    }
    package com.designpattern.Interpreter;
    
    /**
     * 非终结符表达式 -- not
     * @author Json<<json1990@foxmail.com>>
     */
    public class NotExp implements BooleanExp {
        private BooleanExp opernot1;
        
        public NotExp(BooleanExp oper1) {
            opernot1 = oper1;
        }
    
        public boolean Evaluate(Context c) {
            return !(opernot1.Evaluate(c));
        }
    
        public BooleanExp Copy() {
            return new NotExp(opernot1.Copy());
        }
    
        public BooleanExp Replace(String var, BooleanExp exp) {
            return new NotExp(opernot1.Replace(var, exp));
        }
    }

    终结符表达式:

    package com.designpattern.Interpreter;
    
    /**
     * 终结符表达式
     * @author Json<<json1990@foxmail.com>>
     */
    public class VariableExp implements BooleanExp {
        private String name;
        
        public VariableExp(String _name) {
            name = _name;
        }
    
        public boolean Evaluate(Context c) {
            return c.LookUp(name);
        }
    
        public BooleanExp Copy() {
            return new VariableExp(name);
        }
    
        public BooleanExp Replace(String var, BooleanExp exp) {
            if(var.equals(name)) {
                return exp.Copy();
            } else {
                return new VariableExp(name);
            }
        }
    }

     上下文:

    package com.designpattern.Interpreter;
    
    import java.util.Hashtable;
    
    /**
     * 上下文
     * @author Json<<json1990@foxmail.com>>
     */
    public class Context  {
        private Hashtable<String, Boolean> context = new Hashtable<String, Boolean>();
        
        public void Assign(String name, boolean val) {
            context.put(name, new Boolean(val));
        }
        
        public boolean LookUp(String name) {
            return ((Boolean)context.get(name)).booleanValue();
        }
        
        public Context() {
        }
    }

    客户端测试:

    package com.designpattern.Interpreter;
    
    /**
     * 客户端测试
     * @author Json<<json1990@foxmail.com>>
     */
    public class Client  {
        public static void main(String[] args) {
            Context context = new Context();
           
            VariableExp x = new VariableExp("X");
            VariableExp y = new VariableExp("Y");
            VariableExp z = new VariableExp("Z");
    
            context.Assign("X", true);
            context.Assign("Y", false);
            context.Assign("Z", true);
            
            //测试表达式 :(z and x) and (y and (not x))
            BooleanExp expression = new AndExp(new AndExp(z, x),new AndExp(y, new NotExp(x)));
            boolean result = expression.Evaluate(context);
            System.out.println("(z and x) and (y and (not x))表达式结果:" + result);
            
            //测试表达式 :(z and x) or (y and (not x))
            BooleanExp expression1 = new OrExp(new AndExp(z, x),new AndExp(y, new NotExp(x)));
            boolean result1 = expression1.Evaluate(context);
            System.out.println("(z and x) or (y and (not x))表达式结果:" + result1);
        }
    }

    结果:

    (z and x) and (y and (not x))表达式结果:false
    (z and x) or (y and (not x))表达式结果:true

    4、优缺点

    优点:

      易于实现语法:在解释器模式中,一条语法规则用一个解释器对象来解释执行,对于解释器的实现来讲,功能就变得比较简单,只需要考虑这一条语法规则的实现就好了,其它的都不用管。

      易于扩展新的语法:正是由于采用一个解释器对象负责一条语法规则的方式,使得扩展新的语法非常容易,扩展了新的语法,只需要创建相应的解释器对象,在创建抽象语法树的时候使用这个新的解释器对象就可以了。

    缺点:

      引起类爆炸:每个语法都要产生一个非终结符表达式,语法规则比较复杂时,就可能产生大量的类文件,为维护带来了非常多的麻烦。

      采用递归调用方法:每个非终结符表达式只关心与自己有关的表达式,每个表达式需要知道最终的结果,必须一层一层地剥茧,无论是面向过程的语言还是面向对象的语言,递归都是在必要条件下使用的,它导致调试非常复杂。想想看,如果要排查一个语法错误,我们是不是要一个一个断点的调试下去,直到最小的语法单元。

      效率问题:解释器模式由于使用了大量的循环和递归,效率是个不容忽视的问题,特别是用于解析复杂、冗长的语法时,效率是非常低的。

    5、场景

    当有一个语言需要解释执行,并且可以将该语言中的句子表示为一个抽象语法树的时候,可以考虑使用解释器模式。

    注意:
      1、语法相对应该比较简单,太复杂的语法不合适使用解释器模式;

      2、效率要求不是很高,对效率要求很高的情况下,不适合使用解释器模式。

    6、总结

    解释器模式在实际的系统开发中使用的非常少,因为它会引起效率、性能以及维护等问题,一般在大中型的框架型项目能够找到它的身影,比如一些数据分析工具、报表设计工具、科学计算工具等等。

    PS:数学运算常用运算解析工具:Expression4J、MESP(Math Expression String Parser)、Jep等开源的解析工具包,功能都异常强大,而且非常容易使用,效率也还不错!!!

    PS:源码地址   https://github.com/JsonShare/DesignPattern/tree/master 

       

    PS:原文地址  http://www.cnblogs.com/JsonShare/p/7367535.html

      

  • 相关阅读:
    2018福大软工实践第二次结对作业
    2018福大软工实践第一次结对作业
    《构建之法》第三章读书笔记
    《构建之法》第八章读书笔记
    Beta版本冲刺前准备
    项目测评
    Alpha版本事后诸葛亮
    Alpha版本冲刺(十)
    Alpha版本冲刺(九)
    Alpha版本冲刺(八)
  • 原文地址:https://www.cnblogs.com/JsonShare/p/7367535.html
Copyright © 2011-2022 走看看