解释器模式(Interpreter pattern): 解释器模式是行为型的模式,比较少用。使用解释器模式简单来说就是为语言创建解释器。
解释器模式的详解
给定一个语言,解释器模式可以定义出其文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子.
解释器中涉及到的文法,就是符合一定规则的语句结构.
如 abcd……cdef(ab开头,ef结尾,中间N个cd)中,根据N值的不同,可以得到不同的字符串如,abef,abcdef,abcdcdef…。
假设我们有如下推导式
- S ::= abA*ef
- A ::= cd
其中 ::=表示推导,*表示闭包,意思是A可以有0~N个重复,S是初始符号,abef和cd是终结符号。
像这样的从一个具体的符号出发,通过不断地应用一些产生式规则 从而生成一个字符串的集合,我们将描述这个集合的文法称为形式文法。
给定一个语言(如由abcdef六个字符组成的字符串集合),定义它的文法的一种表示(S::=abA*ef,A::=cd)并定义一个解释器,解释器使用该表示来解释语言中的句子。其中的解释器类似一个翻译机。
解释器模式类图:
角色说明:
抽象表达式角色(Expression):抽象表达式,声明一个抽象的解释操作父类,定义一个抽象的解释方法,具体的实现由子类解释器完成。
终结符表达式角色(Terminal Expression):终结符表达式,实现文法中与终结符有关的解释操作,文法中每一个终结符都有一个具体的终结表达式与之对应。
非终结符表达式角色(Nonterminal Expression):非终结符表达式,实现文法中与非终结符有关的解释操作
环境角色(Context):上下文环境类,包含解释器之外的全局信息。
举个形象的例子,一个加法表达式a+b+c,如果我们用解释器模式解释此表达式,那么a、b、c可以看成终结表达式角色,+可以看成非终结表达式。
类图:
代码演示,抽象解释类:
//抽象解释类
public abstract class Expression {
/**
* 解释操作方法
*
* @return
*/
public abstract int interptet();
}
数字解释类:
//数字解释类
public class NumExpression extends Expression {
private int num;
public NumExpression(int num) {
this.num = num;
}
@Override
public int interptet() {
return num;
}
}
运算符解释类:
//运算符解释类
public abstract class SymbolExpression extends Expression {
protected Expression expression1, expression2;
public SymbolExpression(Expression expression1, Expression expression2) {
this.expression1 = expression1;
this.expression2 = expression2;
}
}
加法的解释类:
//加法解释类
public class AddExpression extends SymbolExpression {
public AddExpression(Expression expression1, Expression expression2) {
super(expression1, expression2);
}
@Override
public int interptet() {
return expression1.interptet() + expression2.interptet();
}
}
业务逻辑处理类:
//业务逻辑处理类
public class Calculator {
protected Stack<Expression> expressionStack = new Stack<>();
public Calculator(String expression) {
Expression expression1, expression2;
//以空格分割字符串,所以字符串的符号和数字之间要有一个空格
String[] elements = expression.split(" ");
for (int i = 0; i < elements.length; ++i) {
switch (elements[i].charAt(0)) {
case '+':
expression1 = expressionStack.pop();
expression2 = new NumExpression(Integer.valueOf(elements[++i]));
expressionStack
.push(new AddExpression(expression1, expression2));
break;
default:
expressionStack.push(new NumExpression(Integer
.valueOf(elements[i])));
break;
}
}
}
public int calculate() {
return expressionStack.pop().interptet();
}
}
客户端测试类:
public class Client {
public static void main(String[] args) {
Calculator calculator = new Calculator("23 + 24 + 25");
System.out.println("解释运算结果:" + calculator.calculate());
}
}
运行结果:
解释器模式的适用场景
- 某个简单的语言需要解释执行并且可以将该语言中的语句表示为一个抽象语法树的时候;
- 在某些特定的领域出现不断重复的问题时,可以将该领域的问题转化为一种语法规则下的语句,并构建解释器来解释该语句。
解释器模式的优点:
- 灵活性强,如上边的例子,当我们想对文法规则进行扩展延伸时,只需要增加相应的非终结符解释器,并在构建语法树的时候使用新增的解释器对象进行具体的解释即可。
缺点:
- 因为每一条文法都可以对应至少一个解释器,会生成大量的类,导致后期维护困难,而且对应复杂的文法,构建语法树会显得异常繁琐。