博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式笔记20:解释器模式(Interpreter Pattern)
阅读量:5061 次
发布时间:2019-06-12

本文共 4996 字,大约阅读时间需要 16 分钟。

一、解释器模式的内容

解释器模式(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
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#等面向对象语言开发简单的编译器,如数学表达式解析器、正则表达式解析器等,用于增强这些语言的功能,使之增加一些新的文法规则,用于解释一些特定类型的语句。

 (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)

  • All subclasses of 
  • All subclasses of 

九、参考资料

  1. 《设计模式》主编清华大学出版社

转载于:https://www.cnblogs.com/snowberg/archive/2012/06/18/2618916.html

你可能感兴趣的文章
Rule 1: Make Fewer HTTP Requests(Chapter 1 of High performance Web Sites)
查看>>
sql注入
查看>>
「破解」Xposed强
查看>>
src与href的区别
查看>>
ABAP工作区,内表,标题行的定义和区别
查看>>
《xxx重大需求征集系统的》可用性和可修改性战术分析
查看>>
Python 中 创建类方法为什么要加self
查看>>
关于indexOf的使用
查看>>
【转】JS生成 UUID的四种方法
查看>>
英语单词
查看>>
centos6.8下安装matlab2009(图片转帖)
查看>>
Mongo自动备份
查看>>
求助大神!怎样批量删除数据库表中某个字段中同样的一段字符!
查看>>
VMWARE虚拟机无法访问的三种方法分析
查看>>
enq: SQ - contention
查看>>
cer证书签名验证
查看>>
ant 安装
查看>>
新手Python第一天(接触)
查看>>
vue路由动态加载
查看>>
【原】UIWebView加载本地pdf、doc等文件
查看>>