设计模式——解释器

来源:互联网 发布:电脑编程与技巧 编辑:程序博客网 时间:2024/05/22 12:52

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 {@Overridepublic void interpret(Context ctx) {System.out.println("this is terminalexpression");}}

NonterminalExpression

package com.examples.pattern.interpreter;/** * 非终结符表达式 */public class NonterminalExpression extends AbstractExpression {@Overridepublic 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);}}}

9、 相关模式 

Composite模式:抽象语法树是一个复合模式的实例。

Flyweight模式:说明了如何在抽象语法树中共享终结符。

Iterator:解释器可用一个迭代器遍历该结构。

Visitor:可用来在一个类中维护抽象语法树中的各节点的行为。

原创粉丝点击