九、解释器设计模式
来源:互联网 发布:淘宝网手套 编辑:程序博客网 时间:2024/04/30 22:44
1.介绍
解释器模式是类的行为模式,给定一个语言后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。
解释器模式在实际运用上相对来说少很多,因为很少会自己去构造语言的文法。
2.解释器模式使用场景
- 重复发生的问题可以使用解释器模式。
- 一个简单语法需要解释的场景。
3. 解释器模式的UML类图
由于解释器模式很好使用,下面的术语解释直接复制网络(侵删)
- 解释器模式的结构
抽象解释器:
声明一个所有具体表达式都要实现的抽象接口(或者抽象类),接口中主要是一个interpret()方法,称为解释操作。
具体解释任务由它的各个实现类来完成,具体的解释器分别由终结符解释器TerminalExpression和非终结符解释器NonterminalExpression完成。
终结符表达式:
实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符。终结符一半是文法中的运算单元,比如有一个简单的公式R=R1+R2,在里面R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。
非终结符表达式:
文法中的每条规则对应于一个非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,+就是非终结符,解析+的解释器就是一个非终结符表达式。非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。
环境角色:
这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200。这些信息需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就足够了。
4.解释器模式简单实现
- 抽象的算术运算解释器 ArithmeticExpression
public abstract class ArithmeticExpression { /** * 抽象的解析方法 * 具体的解析逻辑由具体子类实现 * @return */ public abstract int interpret();}
- 数字解释器
public class NumExpression extends ArithmeticExpression { private int num; public NumExpression(int num) { this.num = num; } @Override public int interpret() { return num; }}
- 运算符号抽象解释器,为所有运算符号解释器共性的提取
public class OperationExpression extends ArithmeticExpression { //声明两个成员变量存储运算符号两边的数字解释器 protected ArithmeticExpression exp1, exp2; public OperationExpression(ArithmeticExpression exp1, ArithmeticExpression exp2) { this.exp1 = exp1; this.exp2 = exp2; } @Override public int interpret() { return 0; }}
- 加法运算抽象解释器
public class AdditionExpression extends OperationExpression { public AdditionExpression(ArithmeticExpression exp1, ArithmeticExpression exp2) { super(exp1, exp2); } @Override public int interpret() { return exp1.interpret() + exp2.interpret(); } }
- 处理与解释相关的一些业务:
public class Calculator { //声明一个Stack栈存储并操作所有相关的解释器 private Stack<ArithmeticExpression> expressions = new Stack<ArithmeticExpression>(); public Calculator(String expression) { //声明两个ArithmeticExpressioin类型的临时变量,存储运算符左右两边的数字解释器 ArithmeticExpression exp1, exp2; String[] elements = expression.split(" "); for (int i = 0; i < elements.length; i++) { switch (elements[i].charAt(0)) { case '+': //将栈中的解释器弹出作为运算符号左边的解释器 exp1 = expressions.pop(); //同时将运算符号数组角标下一个元素构成 exp2 = new NumExpression(Integer.valueOf(elements[++i])); //通过上面两个数字解释器构造加法运算解释器 expressions.push(new AdditionExpression(exp1, exp2)); break; default://如果为数字 /** * 如果不是运算符则数字 * 则是数字,直接构造数字解释器并压入栈 */ expressions.push(new NumExpression(Integer.valueOf(elements[i]))); break; } } } /** * 计算 * @return */ public int calculate() { return expressions.pop().interpret(); } }
- 测试类:
public class Client { public static void main(String[] args) { Calculator calculator = new Calculator("100 + 30 + 5"); System.out.println(calculator.calculate()); }}
这里简单说一下Calculator里面的流程,以为”100 + 30 +5”为例:
首先将其拆分为五个元素组成的字符串数组。
循环遍历数组,首先遍历到的是100,那么将其构造成一个NumExpression对象压入栈。
接着遍历到了加号运算符,此时将我们刚刚压入栈的100出栈,作为加号运算符左边的数字解释器。
接着,将当前加号运算符下一个角标构造成一个数字解释器,作为加号运算符右边的数字解释器。
将左右两个数字解释器作为参数传入AdditionExpression构造一个加法解释器,同时压入栈中。
重复步骤3的操作
重复步骤4的操作。
最后调用interpret(),结果相当于exp1.interpret() + exp2.interpret()+exp3.interpret()
5.解释器模式在Android源码中的实现
解释器模式在Android源码中并不常见,这里就不做具体分析了。
6. 总结:
- 优点:
- 灵活的扩展性,当我们想对文法规则进行扩展时,只需要增加相应的非终结符号解释器,并在构建抽象语法树时,使用到新增的解释器对象进行具体的解释即可,非常方便。
- 缺点:
- 过于复杂的语法,构建其抽象语法树会显得异常繁琐,甚至有可能出现需要构建多棵抽象语法树的情况,因此,对于复杂的文法并不推荐使用解释器模式。
- 对于每一条文法都可以对应至少一个解释器,其会生成大量的类,导致后期维护困难。
- 九、解释器设计模式
- Android设计模式(九)-解释器模式
- 【设计模式】解释器
- 设计模式-解释器
- 设计模式:解释器
- 设计模式 解释器模式
- 设计模式-解释器模式
- 设计模式:解释器模式
- 设计模式:解释器模式
- 设计模式-解释器模式
- 设计模式-解释器模式
- 设计模式--解释器模式
- 设计模式-解释器模式
- 设计模式-解释器模式
- [设计模式]解释器模式
- 设计模式-解释器模式
- 设计模式-解释器模式
- 设计模式--解释器模式
- 第一次打字测试
- leetcode-136. Single Number
- 练习三 1023
- JavaScript知识总结—cookie及其应用
- Spring 事务管理笔记
- 九、解释器设计模式
- 感悟
- JavaScript算法
- Eclipse中Maven管理的jar没有发布到WEB-INF/lib下的解决方案
- 共用数据保护(const 常量)
- hibernate反向生成奇葩错误
- leetcode-260. Single Number III
- hdu 5671 Matrix
- karatsuba乘法