设计模式笔记20:解释器模式(Interpreter Pattern)

来源:互联网 发布:卖家设置淘宝客优惠券 编辑:程序博客网 时间:2024/05/16 01:28

一、解释器模式的内容

解释器模式(Interpreter Pattern) :定义语言的文法,并且建立一个解释器来解释该语言中的句子,这里的“语言”意思是使用规定格式和语法的代码,它是一种类行为型模式。

  • 如果在系统中某一特定类型的问题发生的频率很高,此时可以考虑将这些问题的实例表述为一个语言中的句子,因此可以构建一个解释器,该解释器通过解释这些句子来解决这些问题。
  • 解释器模式描述了如何构成一个简单的语言解释器,主要应用在使用面向对象语言开发的编译器中。

二、解释器模式的结构


参与者:
  •     AbstractException:抽象表达式,声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。
  •     TerminalExpression:终结符表达式。实现与文法中的终结符相关联的解释操作,一个句子中的每个终结符需要该类的一个实例。
  •     NonterminalExpression:非终结符表达式,对于文法中的每一条规则R::=R1R2..都需要一个NonterminalExpression类。为从R1Rn的每个符号都维护一个AbstractExpression类型的实例变量。为文法中的非终结符实现解释操作,解释操作一般要递归地调用表示R1Rn的那些对象的解释操作。
  •     Context:上下文,包含解释器需要解释的全局信息。
  •     Client:构建表示该文法定义的语言中一个特定的句子的抽象语法树。该抽象语法树由NonterminalExpressionTerminalExpression的实例装配而成。调用解释操作等。
协作:
  • Client构建一个句子,它是NonterminalExpressionTerminalExpress的实例的一个抽象语法树,然后初始化上下文并调用解释操作。然后初始化上下文并调用解释操作。
  • 每一个非终结符表达式节点定义相应子表达式的解释操作。而各终结符表达式的解释操作构成了递归的基础。
  • 每一节点的解释操作用上下文来存储和访问解释器的状态。

三、解释器模式示例代码

代码一、
public abstract class AbstractExpression{public abstract void interpret(Context ctx);} public class TerminalExpression extends AbstractExpression{public void interpret(Context ctx){//对于终结符表达式的解释操作}}public class NonterminalExpression extends AbstractExpression{private AbstractExpression left;private AbstractExpression right;public NonterminalExpression(AbstractExpression left,AbstractExpression right){this.left=left;this.right=right;}public void interpret(Context ctx){//递归调用每一个组成部分的interpret()方法//在递归调用时指定组成部分的连接方式,即非终结符的功能}}
代码二、
AbstractException:抽象表达式
public interface Node{public int interpret();}
NonterminalExpression:非终结符表达式
public abstract class SymbolNode implements Node{protected Node left;protected Node right;public SymbolNode(Node left,Node right){this.left=left;this.right=right;}}
TerminalExpression:终结符表达式
public class ValueNode implements Node{private int value;public ValueNode(int value){this.value=value;}public int interpret(){return this.value;}}

public class DivNode extends SymbolNode{public DivNode(Node left,Node right){super(left,right);}public int interpret(){return super.left.interpret() / super.right.interpret();}}

public class ModNode extends SymbolNode{public ModNode(Node left,Node right){super(left,right);}public int interpret(){return super.left.interpret() % super.right.interpret();}}

public class MulNode extends SymbolNode{public MulNode(Node left,Node right){super(left,right);}public int interpret(){return super.left.interpret() * super.right.interpret();}}
 Context
import java.util.*;public class Calculator{private String statement;private Node node;        public void build(String statement)    {    Node left=null,right=null;    Stack stack=new Stack();        String[] statementArr=statement.split(" ");        for(int i=0;i<statementArr.length;i++)    {    if(statementArr[i].equalsIgnoreCase("*"))    {    left=(Node)stack.pop();        int val=Integer.parseInt(statementArr[++i]);        right=new ValueNode(val);     stack.push(new MulNode(left,right));    }    else if(statementArr[i].equalsIgnoreCase("/"))    {    left=(Node)stack.pop();        int val=Integer.parseInt(statementArr[++i]);        right=new ValueNode(val);     stack.push(new DivNode(left,right));        }    else if(statementArr[i].equalsIgnoreCase("%"))    {    left=(Node)stack.pop();        int val=Integer.parseInt(statementArr[++i]);        right=new ValueNode(val);     stack.push(new ModNode(left,right));       }    else    {    stack.push(new ValueNode(Integer.parseInt(statementArr[i])));    }    }    this.node=(Node)stack.pop();    }public int compute(){return node.interpret();}}
Client
public class Client{public static void main(String args[]){String statement = "3 * 2 * 4 / 6 % 5";Calculator calculator = new Calculator();calculator.build(statement);int result = calculator.compute();System.out.println(statement + " = " + result);}}

四、解释器模式分析

解释器模式描述了如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如何解释这些句子。
文法规则实例:
expression ::= value | symbol
symbol ::= expression '+' expression | expression '-' expression
value ::= an integer //一个整数值
在文法规则定义中可以使用一些符号来表示不同的含义,如使用“|”表示或,使用“{”和“}”表示组合,使用“*”表示出现0次或多次等,其中使用频率最高的符号是表示或关系的“|” 。
抽象语法树:
除了使用文法规则来定义一个语言,在解释器模式中还可以通过一种称之为抽象语法树(Abstract Syntax Tree, AST)的图形方式来直观地表示语言的构成,每一棵抽象语法树对应一个语言实例。 
抽象语法树描述了如何构成一个复杂的句子,通过对抽象语法树的分析,可以识别出语言中的终结符和非终结符类。 
在解释器模式中,每一种终结符和非终结符都有一个具体类与之对应,正因为使用类来表示每一个语法规则,使得系统具有较好的扩展性和灵活性。 

五、解释器模式扩展

数学表达式解析器简介 
  • 在实际项目开发中如果需要解析数学公式,无须再运用解释器模式进行设计,可以直接使用一些第三方解析工具包,它们可以统称为数学表达式解析器(Math Expression Parser, MEP),如Expression4J、Jep、JbcParser、Symja、Math Expression String Parser(MESP)等来取代解释器模式,它们可以方便地解释一些较为复杂的文法,功能强大,且使用简单,效率较好。
  • Expression4J:Expression4J是一个基于Java的开源框架,它用于对数学表达式进行操作,是一个数学公式解析器,在Expression4J中可以将数学表达式存储在字符串对象中。Expression4J是高度定制的,用户可以自定义文法,其主要功能包括实数和复数的基本数学运算,支持基本数学函数、复杂函数以及用户使用Java语言自定义的函数和文法,还可以定义函数目录(函数集)、支持XML配置文件等。 http://www.expression4j.org/ 
  • Jep:Jep(Java Mathematical Expression Parser)是一个用于解析和求解数学表达式的Java类库。通过使用Jep提供的包,我们可以输入一个以字符串表示的任意数学公式,然后立即对其进行求解。Jep支持用户自定义变量、常量和自定义函数,同时还包含了大量通用的数学函数和常量。 http://www.singularsys.com/jep/  

六、解释器模式优缺点

解释器模式的优点
  1. 易于改变和扩展文法。
  2. 易于实现文法。
  3. 增加了新的解释表达式的方式。
解释器模式的缺点
  1. 对于复杂文法难以维护。
  2. 执行效率较低。
  3. 应用场景很有限。

七、解释器模式适用环境

在以下情况下可以使用解释器模式:
  1. 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
  2. 一些重复出现的问题可以用一种简单的语言来进行表达。
  3. 文法较为简单。 
  4. 效率不是关键问题。

八、解释器模式应用

(1) 解释器模式在使用面向对象语言实现的编译器中得到了广泛的应用,如Smalltalk语言的编译器。
(2) 目前有一些基于Java抽象语法树的源代码处理工具,如在Eclipse中就提供了Eclipse AST,它是Eclipse JDT的一个重要组成部分,用来表示Java语言的语法结构,用户可以通过扩展其功能,创建自己的文法规则。
(3) 可以使用解释器模式,通过C++、Java、C#等面向对象语言开发简单的编译器,如数学表达式解析器、正则表达式解析器等,用于增强这些语言的功能,使之增加一些新的文法规则,用于解释一些特定类型的语句。

Interpreter (recognizeable by behavioral methods returning a structurally different instance/type of the given instance/type; note that parsing/formatting is not part of the pattern, determining the pattern and how to apply it is)

  • java.util.Pattern
  • java.text.Normalizer
  • All subclasses of java.text.Format
  • All subclasses of javax.el.ELResolver

九、参考资料

  1. http://tianli.blog.51cto.com/190322/41998/
  2. 《设计模式》刘伟主编清华大学出版社

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小打架受伤对方家长不配合怎么办 宝宝要上幼儿园了家长该怎么办 断奶涨奶怎么办又能防止乳房变形 孩子在幼儿园被小朋友打了怎么办 孩子在幼儿园被小朋友咬了怎么办 孩子被同学打了家长该怎么办? 孩子把同学打了打人家长该怎么办 孩子和同学发生矛盾家长该怎么办 孩子同学给孩子要东西家长该怎么办 如果遇到不讲理的孩子和家长怎么办 孩子调皮又被老师留校了怎么办 孩子拼音f和sh发音不清怎么办 自己在家生的孩子怎么办出生证明 在家念地藏经招来众生不走怎么办 家是济宁孩子上学想在济南上怎么办 高一孩子成绩严重下滑家长怎么办 商铺租客不交租金又不搬走怎么办 考试试卷找不到了明天要交怎么办 8个月宝宝不爱吃蔬菜泥怎么办 5个月的宝宝拉肚怎么办 一岁宝宝大便拉不出来怎么办 八个月宝宝便秘拉不出来怎么办 10个月宝宝大便拉水怎么办 4个月的孩子大便拉水怎么办 五个多月宝宝大便拉水怎么办 七个月宝宝大便还没成行怎么办 宝宝一岁了还没长牙怎么办 宝宝什么都会就差不会独占怎么办 两岁宝宝肚子不舒服还吐怎么办 两岁宝宝吃坏肚子吐怎么办 1岁半儿童牙烂了怎么办 一岁宝宝吃了就吐怎么办 两岁宝宝龋齿门牙掉了怎么办 一岁宝宝冻着了呕吐怎么办 两岁宝宝喉咙有痰呼呼响怎么办 1岁宝宝吐的水水怎么办 宝宝吐了5 6次了怎么办 7岁儿童吃了就吐怎么办 狗狗拉稀呕吐不吃饭只喝水怎么办 宝宝吃坏肚子上吐下泄怎么办 一岁宝宝又吐又拉怎么办