这是我参与更文挑战的第10天,活动详情查看:更文挑战
解释器模式
解释器模式是一种行为型模式,提供一种解释语言的语法和表达式的方法,定义一个表达式接口,通过接口解释一个特定上下文。但实际上使用解释器模式的场景并不多,相对来说也不太常遇到。不过既然是设计模式中的一种,那必然也有它可用的独特模式。
给定一个语言,定义它的文法一种表示,并定义一个解释器,则解释器使用该表示来解释语言中的句子。
实现
解释器常见场景是对算术表达式的解释。比如表达式m + n + p,如果我们使用解释器模式对表达式进行解释,表示数字的m/n/p可以作为终结符号,”+“可以当做非终结符号。
ArithmeticExpression抽象类定义一个interpret方法。NumExpression用来对数字进行解释,主要目的是获取数字。OperatorExpression是抽象类,声明了两个ArithmeticExpression用于存储NumExpression运算符两边的数字解释器。AdditionExpression继承OperatorExpression实现了加法运算解释器的作用。
实现了文法中对每个结构做解析的解释器之后,再创建一个Calculator类去处理逻辑。输入整个文法内容:"153 + 896 + 789",通过分割将内容不断分割解析成每个对应解释器,最后将解释器组装输出最终结果。
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 abstract class OperatorExpression extends ArithmeticExpression {
public ArithmeticExpression exp1;
public ArithmeticExpression exp2;
public OperatorExpression(ArithmeticExpression exp1, ArithmeticExpression exp2) {
this.exp1 = exp1;
this.exp2 = exp2;
}
}
public class AdditionExpression extends OperatorExpression {
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> mExpStack = new Stack<>();
public Calculator(String expression) {
// 声明两个ArithmeticExpression类型的临时变量,存储运算符左右两边的数字解释器
ArithmeticExpression exp1;
ArithmeticExpression 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 AdditionExpression(exp1, exp2));
break;
default: // 如果为数字
/**
* 如果不是运算符号则为数字
* 若是数字,直接构造数字解释器并压入栈
*/
mExpStack.push(new NumExpression(Integer.valueOf(elements[i])));
break;
}
}
}
public int calculate() {
return mExpStack.pop().interpret();
}
}
Calculator calculator = new Calculator("153 + 896 + 789");
calculator.calculate();
总结
- 解释器模式优点:灵活扩展性,当对文法规则进行扩展延伸时,只需要添加相应非终结符解释器,在构建抽象语法树时使用新增解释器对象进行解释即可。
- 解释器模式优点:对于每一条文法要至少对应一个解释器,类数量庞大,后期维护困难。如果文法是复杂抽象的,那么构建使用解释器模式并不非常合适的选择。
参考
- 《Android源码设计模式》