第十章、解释器模式
解释器模式是一种用的比較少的行为型模式。其提供了一种解释语言的语法或表达式的方式。
可是它的使用场景确实非常广泛,仅仅是由于我们自己非常少回去构造一个语言的文法,所以使用较少。
1.定义
给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
(当中语言就是我们须要解释的对象,文法就是这个语言的规律,解释器就是翻译机。通过文法来翻译语言。)
2.使用场景
1.假设某个简单的语言须要解释运行并且能够将该语言中的语句表示为一个抽象的语法树时能够考虑使用解释器模式。
2.在某些特定的领域出现不断反复的问题时,能够将该领域的问题转化为一种语法规则下的语句。然后构建解释器来解释该语句。
3.简单实现
我们使用解释器模式对“m+n+p”这个表达式进行解释,那么代表数字的m、n和p就能够看成终结符号,而“+”这个运算符号能够当做非终结符号。
TerminalExpression:终结符表达式,实现文法中与终结符有关的解释操作。
文法中每一个终结符都有一个详细的终结表达式与之相应。
NonterminalExpression :非终结符表达式,实现文法中与非终结符有关的解释操作。非终结符表达式依据逻辑的复杂程度而添加。原则上每一个文法规则都相应一个非终结符表达式。
抽象的算数运算解释器
public abstract class ArithemticExpression {
/**
* 抽象的解析方法
* 详细的解析逻辑由详细的子类实现
*
* @return 解析得到详细的值
*/
public abstract int interpreter();
}
数字解释器
public class NumExpression extends ArithemticExpression{
private int num;
public NumExpression(int num){
this.num = num;
}
@Override
public int interpreter() {
return num;
}
}
运算符号解释器
public abstract class OperatorExpression extends ArithemticExpression{
protected ArithemticExpression exp1, exp2;
public OperatorExpression(ArithemticExpression exp1, ArithemticExpression exp2){
this.exp1 = exp1;
this.exp2 = exp2;
}
}
详细的加法运算符解释器
public class AdditionExpression extends OperatorExpression{
public AdditionExpression(ArithemticExpression exp1,
ArithemticExpression exp2) {
super(exp1, exp2);
}
@Override
public int interpreter() {
return exp1.interpreter() + exp2.interpreter();
}
}
处理解释器
public class Calculator {
//声明一个Stack栈储存并操作全部相关的解释器
private Stack<ArithemticExpression> mExpStack = new Stack<ArithemticExpression>();
public Calculator(String expression){
//声明两个ArithemticExpression类型的暂时变量,储存运算符左右两边的数字解释器
ArithemticExpression exp1,exp2;
//依据空格切割表达式字符串(比方1 + 2 + 3 + 4)
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.parseInt(elements[++i]));
//通过上面的两个数字解释器构造加法运算解释器
mExpStack.push(new AdditionExpression(exp1, exp2));
break;
default:
/*
* 假设为数字,直接构造数字解释器并压入栈
*/
mExpStack.push(new NumExpression(Integer.valueOf(elements[i])));
break;
}
}
}
/**
* 计算结果
*
* @return 终于的计算结果
*/
public int calculate(){
return mExpStack.pop().interpreter();
}
}
调用
public class Client {
public static void main(String[] args) {
Calculator c = new Calculator("22 + 553 + 83 + 5");
System.out.println("计算结果:"+c.calculate());
}
}
结果:
计算结果:663
假设相加如减法的操作,在Calculator中添加相应推断就可以:
public class SubtractionExpression extends OperatorExpression{
public SubtractionExpression(ArithemticExpression exp1,
ArithemticExpression exp2) {
super(exp1, exp2);
}
@Override
public int interpreter() {
return exp1.interpreter() - exp2.interpreter();
}
}
Calculator中添加:
case '-':
exp1 = mExpStack.pop();
exp2 = new NumExpression(Integer.parseInt(elements[++i]));
mExpStack.push(new SubtractionExpression(exp1, exp2));
break;
从上面能够看出解释器模式非常灵活,他将复杂问题能够简单化、模块化、分离实现、解释运行。
4.Android源代码中的模式实现
1.PackageParser
PackageParser是对AndroidManifest.xml配置文件进行读取的,详细原理參考:解析AndroidManifest原理
5.总结
1.长处
最大的长处使其灵活的扩展性,当我们想对文法规则进行扩展延伸时。仅仅须要添加相应的非终结符解释器,并在构建抽象语法树时。使用到新增的解释器对象进行详细的解释就可以,非常方便。
2.缺点
1.每一个语法都要产生一个非终结符表达式,语法规则比較复杂时。就可能产生大量的类文件,为维护带来了非常多的麻烦。
2.解释器模式由于使用了大量的循环和递归。效率是个问题,特别是用于解析复杂、冗长的语法时,效率是难以忍受的。
6.參考
參考链接:解释器模式 详细解释