INTERPRETER 解释器
1、 意图
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
2、 适用性
当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好:
3、 结构
4、 参与者
AbstractExpression(抽象表达式)
——声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。
TerminalExpression(终结符表达式)
——实现与文法中的终结符相关联的解释操作。
——一个句子中的每个终结符需要该类的一个实例。
NonterminalExpression(非终结符表达式)
——对文法中的每一条规则R::=都需要一个NonterminalExpression。
——为从到的每个符号都维护一个AbstractExpression类型的实例变量。
——为文法中的非终结符实现解释操作。解释一般要递归地调用表示到的那些对象的解释操作。
Context(上下文)
——包含解释器之外的一些全局信息。
Client(客户)
——构建(或被给定)表示该文法定义的语言中一个特定的句子的抽象语法树。该抽象树语法由NonterminalExpression和TerminalExpression的实例装配而成。
——调用解释操作。
5、 协作
l Client构建(或被给定)一个句子,它是NonterminalExpression和TerminalExpression的实例的一个抽象语法树,然后初始化上下文并调用解释操作。
l 每一非终结符表达式节点定义相应子表达式的解释操作。而各终结符表达式的解释操作构成了递归的基础。
l 每一节点的解释操作用上下文来存储和访问解释器的状态。
6、 效果
解释器模式有下列的优点和不足:
1) 易于改变和扩展文法;因为该模式使用类来表示文法规则,你可使用继承来改变或扩展该文法。已有的表达式可被增量式地改变,而新的表达式可定义为旧表达式的变体。
2) 也易于实现文法;定义抽象语法树中各个节点的类的实现大体类似。这些类易于直接编写,通常它们也可用一个编译器或语法分析程序生成器自动生成。
3) 复杂的文法难以维护;解释器模式为文法中的每一条规则至少定义了一个类。因此包含许多规则的文法可能难以管理和维护。可应用其他的设计模式来缓解这一问题。
4) 增加了新的解释表达式的方式;解释器模式使得实现新表达式“计算”变得容易。
7、 实现
1) 创建抽象语法树;解释器模式并未解释如何创建一个抽象的语法树。换言之,它不涉及语法分析。抽象语法树可用一个表驱动的语法分析程序来生成,也可用手写的(通常为递归下降法)语法分析程序创建,或直接由Client提供。
2) 定义解释操作;并不一定要在表达式类中定义解释操作。如果经常要创建一种新的解释器,那么使用Visitor模式将解释放入一个独立的“发问者”对象更好。
3) 与Flyweight模式共享终结符;在一些文法中,一个句子可能多次出现同一个终结符。此时最好共享那个符号的单个拷贝。
终结节点通常不存储关于它们在抽象语法树中的位置的信息。在解释过程中,任何它们所需要的上下文信息都由父节点传递给它们。因此在共享的(内部的)状态和传入的(外部的)状态区分得很明确,这就用到了Flyweight模式。
8、 代码示例
AbstractExpression
package com.examples.pattern.interpreter;
/**
* 抽象表达式
*/
public abstract class AbstractExpression {
public abstract void interpret(Context ctx);
}
TerminalExpression
package com.examples.pattern.interpreter;
/**
* 终结符表达式
*/
public class TerminalExpression extends AbstractExpression {
@Override
public void interpret(Context ctx) {
System.out.println("this is terminalexpression");
}
}
NonterminalExpression
package com.examples.pattern.interpreter;
/**
* 非终结符表达式
*/
public class NonterminalExpression extends AbstractExpression {
@Override
public void interpret(Context ctx) {
System.out.println("this is nonterminalexpression");
}
}
Context
package com.examples.pattern.interpreter;
import java.util.ArrayList;
import java.util.List;
/**
* 上下文
*/
public class Context {
private String content;
private List list = new ArrayList();
public void setContent(String content) {
this.content = content;
}
public String getContent() {
return this.content;
}
public void add(AbstractExpression eps) {
list.add(eps);
}
public List getList() {
return list;
}
}
Client
package com.examples.pattern.interpreter;
import java.util.Iterator;
import java.util.List;
public class Client {
public static void main(String[] args) {
Context ctx = new Context();
ctx.add(new TerminalExpression());
ctx.add(new NonterminalExpression());
ctx.add(new TerminalExpression());
List list = ctx.getList();
Iterator it = list.iterator();
while (it.hasNext()) {
AbstractExpression ae = (AbstractExpression) it.next();
ae.interpret(ctx);
}
}
}
Composite模式:抽象语法树是一个复合模式的实例。
Flyweight模式:说明了如何在抽象语法树中共享终结符。
Iterator:解释器可用一个迭代器遍历该结构。
Visitor:可用来在一个类中维护抽象语法树中的各节点的行为。