`
wangwengcn
  • 浏览: 176227 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

21.解析器模式(Interpreter Pattern)

阅读更多

1.定义

给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子。
属于行为类模式。

 

2.解释器模式的使用场景

  • 重复发生的问题可以使用解释器模式:比如根据用户输入的公式进行加减乘除四则运算,但是他们输入的公式每次都不同,有时是a+b-c*d,有时是a*b+c-d,等等等等个,公式千变万化,但是都是由加减乘除四个非终结符来连接的,这时我们就可以使用解释器模式。
  • 一个简单语法需要解释的场景:你看看下面给出的例子,非终结表达式,文法规则越多,复杂度越高,而且类间还要进行递归调用。因此解释器模式一般用来解析比较标准的字符集,例如sql语法分析,不过该部分逐渐被专用工具所取代。

在实际开发工作中经常会有客户要求计算公式他们自己制定,我们只要按照他们的公式和提供的数据进行运算就行了,那么这个业务逻辑也就不能写死了。
下面让我们工具加减乘除四则运算的例子来看看何谓解释器模式(四则比较麻烦,例子只写加减操作):

 

package _21InterpretePattern;

import java.util.HashMap;

/**
 * 抽象表达式
 */
public abstract class Expression {
	
	/**
	 * 解析公式和数值,其中var中的key是公式的参数,value值是具体的数字
	 * 负责对传递进来的参数和值进行解析和匹配,其中key是表达式a+b+c中的a、b、c,value是运算时取得的值
	 */
	// 如果是终结符表达式,那么此方法将获取参数的值
	// 如果是非终结符表达式,那么此方法将进行运算,比如加减
	public abstract int interpreter(HashMap<String, Integer> var);
}
 
package _21InterpretePattern;

import java.util.HashMap;

/**
 * 变量解析器
 * 终结符表达式
 */
public class VarExpression extends Expression {
	
	private String key;

	public VarExpression(String key) 
	{
		this.key = key;
	}

	// 从map中取得值
	@Override
	public int interpreter(HashMap<String, Integer> var) {
		return var.get(key);
	}

}
 
package _21InterpretePattern;

/**
 * 抽象运算符解析器
 * 非终结符表达式
 */
public abstract class SymbolExpression extends Expression {
	
	// 每个运算符都有左右两个参数进行运算,因此抽象到父类中
	protected Expression left;
	protected Expression right;

	public SymbolExpression(Expression left, Expression right)
	{
		this.left = left;
		this.right = right;
	}

}
 
package _21InterpretePattern;

import java.util.HashMap;

/**
 * 加法解析器
 * interpreter方法处理加法运算
 */
public class AddExpression extends SymbolExpression {

	public AddExpression(Expression left, Expression right) {
		super(left, right);
	}

	// 进行加法运算
	@Override
	public int interpreter(HashMap<String, Integer> var) {
		return super.left.interpreter(var) + super.right.interpreter(var);
	}

}
 
package _21InterpretePattern;

import java.util.HashMap;

/**
 * 减法解析器
 * interpreter方法处理减法运算
 */
public class SubExpression extends SymbolExpression {

	public SubExpression(Expression left, Expression right) {
		super(left, right);
	}

	// 进行减法运算
	@Override
	public int interpreter(HashMap<String, Integer> var) {
		return super.left.interpreter(var) - super.right.interpreter(var);
	}

}
 
package _21InterpretePattern;

import java.util.HashMap;
import java.util.Stack;

/**
 * 对输入的表达式进行解析,并计算
 */
public class Context {

	// 定义表达式,最后拿到是一个运算解析器,比如X+Y格式的,其中X可能又是由A+B的运算解析器组成
	// 只有最底层的解析器才是变量解析器,也就是终结符表达式
	// 此参数最终得到的肯定是非终结表达式
	private Expression expression;
	
	/**
	 * 分析用户输入的表达式
	 */
	public void analyse(String expStr) {
		// 定义一个栈,安排运算的先后顺序
		Stack<Expression> stack = new Stack<Expression>();
		char[] charArray = expStr.toCharArray();
		Expression left = null;
		Expression right = null;
		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));
				break;
			case '-':
				// 将减法运算加入到栈中
				left = stack.pop();
				right = new VarExpression(String.valueOf(charArray[++i]));
				stack.push(new SubExpression(left, right));
				break;
			default:
				// 如果不是运算符,那么就是终结表达式
				stack.push(new VarExpression(String.valueOf(charArray[i])));
			}
		}
		// 把最终栈的顶层抛出,它即是最后封装的非终结表达式
		this.expression = stack.pop();
	}
	
	// 将键值对输入给表达式运算
	public int run(HashMap<String, Integer> var)
	{
		return expression.interpreter(var);
	}
}
 
package _21InterpretePattern;

import java.util.HashMap;

/**
 * 场景类
 */
public class Client {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		String expStr = "a+b-c+d";
		HashMap<String, Integer> var = new HashMap<String, Integer>();
		var.put("a", 1);
		var.put("b", 2);
		var.put("c", 2);
		var.put("d", 4);
		
		Context context = new Context();
		// 先解析运算表达式
		context.analyse(expStr);
		// 进行运算
		System.out.println(context.run(var));
	}

}

 

3.解释器模式的四个角色

  • AbstractExpression抽象解释器:声明一个所有具体表达式都要实现的抽象接口(或者抽象类),接口中主要是一个interpreter()方法,称为解释操作。具体解释任务由它的各个实现类来完成,具体的解释器分别由终结符解释器TerminalExpression和非终结符解释器NonterminalExpression完成。
  • TerminalExpression终结符表达式:实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符。终结符一半是文法中的运算单元,比如有一个简单的公式R=R1+R2,在里面R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。
  • NonterminalExpression非终结符表达式:文法中的每条规则对应于一个非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,+就是非终结符,解析+的解释器就是一个非终结符表达式。非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。
  • Context环境角色:这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200。这些信息需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就足够了。

 

4.解释器模式的优点

解释器是一个简单的语法分析工具,它最显著的优点就是扩展性,修改语法规则只需要修改相应的非终结符就可以了,若扩展语法,只需要增加非终结符类就可以了。

 

5.解释器模式的缺点

  • 解释器模式会引起类的膨胀:每个语法都需要产生一个非终结符表达式,语法规则比较复杂时,就可能产生大量的类文件,为维护带来非常多的麻烦。
  • 解释器模式采用递归调用方法:每个非终结符表达式只关心与自己相关的表达式,每个表达式需要知道最终的结果,必须通过一层一层的剥茧,无论是面向对象的语言还是面向过程的语言,递归都是一个不推荐的方式(只在必要条件下使用),它将导致调试非常复杂。想想看,如果要排查一个错误,我们是不是要一个个断点调试下去,直至最小的语法单元。
  • 解释器模式使用了大量的循环和递归:效率是一个不容忽视的问题。特别是用于解释一个解析复杂、冗长的语法时,效率是难以忍受的。

6.解释器模式的注意事项

尽量不要在重要模块中使用解释器模式,否则维护会是一个很大的问题。在项目中可以使用shell、JRuby、Groovy等脚本语言来代替解释器模式、弥补Java编译型语言的不足。我们在一个银行的分析型项目中就采用了JRuby进行运算处理,避免使用解释器模式的四则运算,效率和性能各方面表现良好。

解释器模式在实际的系统开发中使用的非常少,因为它会引起效率、性能以及维护等问题,一般在大中型的框架型项目中能找到它的身影,如一些数据分析工具、报表设计工具、科学计算工具等,如果你确实遇到“一种特定类型的问题发生的频率足够高”的情况,准备使用解释器模式时,可以考虑一下Expression4J、MESP、Jep 等开源的解析工具包,功能都非常强大,而且非常容易使用,效率也不错,实现大多数的数学运算完全没有问题,自己没有必要重头开始编写解释器。

分享到:
评论

相关推荐

    InterpreterPattern.rar

    本项目“InterpreterPattern.rar”是基于Qt C++框架开发的一个计算器应用程序,巧妙地融合了解析器模式和状态机模式,旨在帮助开发者更好地理解和应用这两种设计模式。 首先,让我们深入解析器模式(Interpreter ...

    设计模式之解释器模式(Interpreter Pattern)

    **设计模式之解释器模式(Interpreter Pattern)** 解释器模式是一种行为设计模式,它提供了一种方式来表示语言的语法,并实现一个解释器用于解析这种语法的语句。这种模式通常用于小型、特定领域的语言(DSL)实现,...

    java 23中设计模式 精华版

    14. 解释器模式(Interpreter Pattern):给定一种语言,定义它的文法表示,并提供一个解释器,用于处理这种语言中的句子。 15. 迭代器模式(Iterator Pattern):提供一种方法顺序访问聚合对象的元素,而又不暴露...

    java设计模式.txt

    解释器模式(Interpreter Pattern) 解释器模式定义了一个语言的文法,并定义了一个解释器来解释该语言中的句子。这里的“语言”是指使用规定格式和语法的代码。 #### 23. 享元模式(Flyweight Pattern) 享元模式...

    Head-First-Design-Patterns-master设计模式官方源码

    17. 解释器模式(Interpreter Pattern):解释器模式给定一个语言,定义它的文法表示,并提供一个解释器来解析该文法表示并执行语言定义的行为。 18. 职责链模式(Chain of Responsibility Pattern):职责链模式...

    scala design patterns源书代码

    14. 解释器模式(Interpreter Pattern):Scala的函数式特性使其非常适合实现解释器模式,通过构建表达式树来执行计算。 15. 命令模式(Command Pattern):Scala的函数和高阶函数使得实现命令模式变得简单,可以...

    C++面向对象23种设计模式实现源码DesignPattern.zip

    1. **解释器模式(Interpreter Pattern)**:解释器模式主要用于创建一个解析特定语言的解释器。在23.解释器模式Interpretor中,可以看到如何通过组合简单元素来构建复杂的表达式解析过程,这在需要自定义语法或...

    C++设计模式课件25_Interpreter.pdf

    从提供的文件信息中,我们可以推断该课件《C++设计模式课件25_Interpreter.pdf》是关于C++语言实现设计模式中的解释器模式(Interpreter Pattern)的一部分教学资料。文件中出现的网站***和网易云课堂是指两个在线...

    常见的23个设计模式详解

    解释器模式(Interpreter Pattern) 解释器模式给出了评估语言的文法规则的一种方法。这种模式适用于当需要一个编译器或解释器来解释语言时,或者一个解析器来解析输入字符串时。 ### 23. 亨元模式(Flyweight ...

    c++-设计模式之解释器模式(Interpreter)

    解释器模式(Interpreter Pattern)是一种行为型设计模式,用于为特定语言的句法定义一个解释器。它通过定义一个语言的文法表示以及解释器的实现来解析和执行表达式。这种模式通常用于设计语言、脚本或规则引擎。 ...

    JAVA中的23中设计模式

    解释器模式(Interpreter Pattern) 解释器模式给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。例如,解析表达式或者小型脚本语言。 #### 23. 享元模式...

    設計模式速查表

    8. 解释器模式(Interpreter Pattern) 解释器模式为特定问题定义一个语言的文法,并为该文法提供一个解释器。解释器模式提供了一个解释句子含义的方式,适用于简单的语言解析场景。 9. 责任链模式(Chain of ...

    java中的23种设计模式

    解释器模式(Interpreter Pattern) 解释器模式定义了如何评估语言的文法规则,它适用于编译器和简单的脚本引擎的实现。 ### 13. 观察者模式(Observer Pattern) 观察者模式定义了对象间的一种一对多依赖关系,...

    解释器模式(Interpreter)原理图

    解释器模式(Interpreter Pattern)是一种行为型设计模式,它用于定义一个语言的文法,并解析语言中的表达式。具体来说,解释器模式通过定义一个解释器来解释语言中的表达式,从而实现对语言的解析和执行。 在解释...

    C#设计模式(23种设计模式)

    解释器模式(Interpreter Pattern) 解释器模式提供了一种方法来定义语言的语法及其解释器。这种模式非常适合于处理文法解析的问题。在C#中,可以通过定义抽象语法树节点和解释器来实现解释器模式。 #### 18. ...

    24个设计模式与6大设计原则

    解释器模式(Interpreter Pattern) 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。 #### 23. 享元模式(Flyweight Pattern) 运用共享技术有效地支持大量细...

    java开发模式

    解释器模式(Interpreter Pattern) 解释器模式定义了一个语言的文法,并且构建一个解释器来解释该语言中句子的意思。解释器模式适用于定义简单的文法规则,例如解析简单的表达式。 #### 19. 装饰者模式...

    设计模式解析_DesignPattern.zip

    - 解释器模式(Interpreter):提供一种语言的文法表示,并定义了如何解释该文法中的句子。 - 迭代器模式(Iterator):提供一种方法顺序访问聚合对象的元素,而不暴露其底层表示。 - 中介者模式(Mediator):...

    软件体系结构期末考试试题.doc

    10. 解释器模式(Interpreter Pattern)常用于解析简单的语言或表达式。工作流语言的解释器需要处理不同的活动节点,执行、记录日志、调用外部应用程序等功能,可以通过组合多个解释器或策略来实现。 这些设计模式...

    23种设计模式全解析.pdf

    11. 解释器模式(Interpreter):给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。 除了上述三大类,还有两类模式与并发编程相关,分别是: 1. 并发型模式...

Global site tag (gtag.js) - Google Analytics