简介
解释器模式(Interpreter Pattern):给定一个语言,定义文法的一种表示,并定义一个解释器,使用该表示解释语言中的句子。
- 为了更好的描述特定的问题,可以创建新的语言,拥有自己的表达式和结构,即文法规则。可使用解释器模式设计语言。
- 文法规则:符号“::=”表示“定义为”,“|”表示或,“{”和“}”表示组合,“*”表示出现0次或多次。其中使用频率最高的符号是表示“或”关系的“|”,如文法规则“boolValue ::= 0 | 1”表示终结符表达式boolValue的取值可以为0或者1。
expression ::= value | operation
operation ::= expression '+' expression | expression '-' expression
value ::= an integer //一个整数值
- 抽象语法树:可以通过终结符表达式value和非终结符表达式operation组成复杂的语句。每个文法规则的语言实例都可以表示为一个抽象语法树。
结构和实现
- 角色包括:
- 抽象表达式:声明抽象解释操作,是所有终结符表达式、非终结符表达式的父类。
- 终结符表达式:句子中的每一个终结符都是该类的一个实例。
- 非终结符表达式:对应句子中的非终结符,可通过递归实现操作。
- 环境类:除解释器之外的全局信息,通常临时存储需要解释的语句,或者解释器共有的功能。
- 解释器的结构。
实例
- 开发机器人控制程序,通过英文控制,每个表达式包括移动方向、方式、距离,表达式之间通过and连接,例如: down run 10 and left move 20。
- 抽象语法树。
- 控制程序结构。
- 指令处理类,将语句解析成结点树。
public class InstructionHandler {
private AbstractNode node;
public void handle(String instruction) {
AbstractNode left = null, right = null;
AbstractNode direction = null, action = null, distance = null;
Stack stack = new Stack(); //声明一个栈对象用于存储抽象语法树
String[] words = instruction.split(" "); //以空格分隔指令字符串
for (int i = 0; i < words.length; i++) {
//本实例采用栈的方式来处理指令,如果遇到“and”,则将其后的三个单词作为三个终结符表达式连成一个简单句子SentenceNode作为“and”的右表达式,而将从栈顶弹出的表达式作为“and”的左表达式,最后将新的“and”表达式压入栈中。 if (words[i].equalsIgnoreCase("and")) {
left = (AbstractNode)stack.pop(); //弹出栈顶表达式作为左表达式
String word1= words[++i];
direction = new DirectionNode(word1);
String word2 = words[++i];
action = new ActionNode(word2);
String word3 = words[++i];
distance = new DistanceNode(word3);
right = new SentenceNode(direction,action,distance); //右表达式
stack.push(new AndNode(left,right)); //将新表达式压入栈中
}
//如果是从头开始进行解释,则将前三个单词组成一个简单句子SentenceNode并将该句子压入栈中
else {
String word1 = words[i];
direction = new DirectionNode(word1);
String word2 = words[++i];
action = new ActionNode(word2);
String word3 = words[++i];
distance = new DistanceNode(word3);
left = new SentenceNode(direction,action,distance);
stack.push(left); //将新表达式压入栈中
}
}
this.node = (AbstractNode)stack.pop(); //将全部表达式从栈中弹出
}
public String output() {
String result = node.interpret(); //解释表达式
return result;
}
}
优缺点和适用范围
- 优点:
- 易于修改文法。通过类表示文法,可以使用继承扩展和改变,符合开闭原则。
- 方便实现。每条文法规则可以表示未一个类,方法实现一个简单语言。
- 缺点:
- 复杂文法难维护。每一条规则需要定义一个类,文法太多,则导致类难以管理和维护,可以考虑使用语法分析程序代替。
- 执行效率低。使用大量循环和递归,效率低,调试困难。
- 适用范围:
- 需要将语句表示为抽象语法树。
- 重复出现的问题可用简单语言表示。
- 执行效率影响不大。
jdk中的应用
- java.util.Pattern类,通过compile方法编译正则表达式这一种语言,并与字符串匹配。
- Pattern详解。