参考
- 《设计模式:可复用面向对象软件的基础 》5.3 Interpreter 解释器 类行为型模式
- 《Android源码设计模式解析与实战》第10章 化繁为简的翻译机--解释器模式
意图
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器适用该表示来解释语言中的句子。
适用场景
当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好:
- 该文法简单对于复杂的文法,文法的类层次变得庞大而又无法管理。
- 效率不是一个关键问题最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先将它们转换为另一种形式。
非终结符号与终止符号
例:
S ::= abA*ef
A ::= cd
符号“::=”表示推导;符号“*”表示闭包,意思就是符号A可以有0或有N个重复;S和A称为非终结符号,因为他们能推导出式子右边的表达式,同时又因为整个推导式是从S出发的,因此,这个S也称为初始符号;而abef和cd这些字符不能再被推导我们称之为终结符号。
结构
- AbstractExpression 抽象表达式,声明一个抽象的解释操作父类,并定义了一个抽象的解释方法,其具体的实现在各个具体的子类解释器中完成。
- TeminalExpression 终结符表达式,实现文法中与终结符有关的解释操作。
- NonterminalExpression 非终结符表达式,实现文法中与非终结符有关的解释操作。
- Context 上下文环境类,包含解释器之外的全局信息。
- Client 客户端类,解析表达式,构建抽象语法树,执行具体的解释表达操作等。
优点
灵活的扩展性,当我们想对文法规则进行扩展延伸时,只需要增加相应的非终结符解释器,并在构建抽象语法树时,使用到新增的解释器对象进行具体的解释即可,比较方便。
缺点
每一条文法都对应一个解释器,会生成大量类,导致后期维护困难。同时,对于过于复杂的文法,构建其抽象语法树会显得异常繁琐,因此,对于复杂的文法并不推荐使用解释器模式。
例子1
描述
表达式“m+n+p”,如果我们使用解释器模式对该表达式进行解释,那么代表数字的m,n,和p三个字母我们就可以看成是终结符号,而“+”这个算术运算符号则可当作非终结符,同时我们可以先创建一个抽象解释器表示数学运算。
结构
代码实现
/**
* 算术运算解释器抽象类
* @author newtrekWang
* @email wangjiaxing20160101@gmail.com
* @time 2018/8/19 23:22
*/
public abstract class AthmeticExpression {
/**
* 抽象的解析方法
* @return 解析得到的值
*/
abstract int interpreter();
}
/**
* 数字解释器,只为了解释数字
* @author newtrekWang
* @email wangjiaxing20160101@gmail.com
* @time 2018/8/19 23:24
*/
public class NumExpression extends AthmeticExpression {
private int num;
public NumExpression(int num){
this.num = num;
}
@Override
int interpreter() {
return num;
}
}
/**
* 运算符解释器
* @author newtrekWang
* @email wangjiaxing20160101@gmail.com
* @time 2018/8/19 23:27
*/
public abstract class OperatorExpression extends AthmeticExpression {
/**
* 运算符两边的表达式
*/
protected AthmeticExpression exp1,exp2;
public OperatorExpression(AthmeticExpression exp1, AthmeticExpression exp2) {
this.exp1 = exp1;
this.exp2 = exp2;
}
}
/**
* 加法解释器
* @author newtrekWang
* @email wangjiaxing20160101@gmail.com
* @time 2018/8/19 23:29
*/
public class AdditionExpressoin extends OperatorExpression {
public AdditionExpressoin(AthmeticExpression exp1, AthmeticExpression exp2) {
super(exp1, exp2);
}
/**
* 具体解释+符号
* @return 解释结果
*/
@Override
int interpreter() {
return exp1.interpreter()+exp2.interpreter();
}
}
/**
* 计算器类
* @author newtrekWang
* @email wangjiaxing20160101@gmail.com
* @time 2018/8/19 23:30
*/
public class Calculator {
/**
* 用一个栈存储并操作所有相关的解释器
*/
private Stack<AthmeticExpression> mExpStack = new Stack<>();
public Calculator(String expression){
AthmeticExpression exp1,exp2;
// 以空格分开元素
String[] elements = expression.split(" ");
for (int i = 0;i<elements.length;i++){
switch (elements[i].charAt(0)){
// 如果为‘+’
case '+':
// 将栈中的解释器弹出作为运算符左边的解释器
exp1 = mExpStack.pop();
// 同时将运算符数组下标下一个元素构造为一个数字解释器
exp2 = new NumExpression(Integer.valueOf(elements[++i]));
mExpStack.push(new AdditionExpressoin(exp1,exp2));
break;
default:
// 如果为数字
mExpStack.push(new NumExpression(Integer.valueOf(elements[i])));
break;
}
}
}
/**
* 最终结算结果
* @return
*/
public int calculate(){
return mExpStack.pop().interpreter();
}
}
public static void main(String[] args){
Calculator calculator = new Calculator("3 + 8 + 2");
System.out.println(calculator.calculate());
}
输出结果:
13