描述
定义
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
类型
类行为型模式
动机
如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。
UML类图
实现
主要角色
- AbstractExpression:抽象表达式
- 声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。
- TerminalExpression:终结符表达式
- 实现与方法中的终结符相关联的解释操作。
- 一个句子中的每个终结符需要该类的一个实例。
- NonterminalExpression:非终结符表达式
- 对方法中的每一条规则R::=R1R2…Rn都需要一个NonterminalExpression类。
- 为从R1到Rn的每个符号都维护一个AbstractExpression类型的实例变量。
- 为文法中的非终结符实现解释(Interpret)操作。解释一般要递归地调用表示R1到Rn的那些对象的解释操作。
- Context:上下文
- 包含解释器之外的一些全局信息。
- Client:客户类
- 构建(或被给定)表示该文法定义的语言中一个特定的句子的抽象语法树。
- 调用解释操作。
示例
-
Context:上下文
public class Context { // 定义解释器之外的一些全局信息 }
-
AbstractExpression:抽象表达式
interface AbstractExpression { Object interpreter(Context ctx); }
-
TerminalExpression:终结符表达式,解释操作构成了递归的基础。
public class TerminalExpression implements AbstractExpression { @Override public Object interpreter(Context ctx) { System.out.println("调用终结符表达式"); return null; } }
-
NonterminalExpression:非终结符表达式,定义相应子表达式的解释操作。
public class NonterminalExpression implements AbstractExpression { public NonterminalExpression(AbstractExpression...expressions) { } @Override public Object interpreter(Context ctx) { System.out.println("调用非终结符表达式"); return null; } }
-
Client:客户类,构建(或被给定)一个句子,然后初始化上下文并调用解释操作。
public class Client { public static void main(String[] args) { Context ctx = new Context(); AbstractExpression expression1 = new TerminalExpression(); AbstractExpression expression2 = new TerminalExpression(); AbstractExpression exp = new NonterminalExpression(expression1, expression2); exp.interpreter(ctx); } }
适用场景
- 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
- 一些重复出现的问题可以用一种简单的语言来进行表达,比如一个sql语句。
优点
- 易于改变和扩展文法。因为该模式使用类来表示文法规则,因此可以使用继承来改变或扩展该文法。已有的表达式可被增量式地改变,而新的表达式可定义为旧表达式的变体。
- 易于实现文法。定义抽象语法树中各个节点的类的实现大体类似。这些类易于直接编写,通常它们也可用一个编译器或语法分析程序生成器自动生成。
- 增加了新的解释表达式的方式。解释器模式使得实现新表达式“计算”变得容易。
缺点
- 复杂的文法难以维护。解释器模式为文法中的每一条规则至少定义了一个类。因此包含许多规则的文法可能难以管理和维护。
- 引起类膨胀。每个语法都需要产生一个非终结符表达式,语法规则比较复杂时,就可能产生大量的类文件,为维护带来非常多的麻烦。
- 执行效率较低。解释器模式采用递归调用方法。由于使用了大量的循环和递归,效率是一个不容忽视的问题。特别是用于解释一个解析复杂、冗长的语法时,效率是难以忍受的。
相关模式
- Composite:抽象语法树是一个复合模式的实例。解释器模式并未解释如何创建一个抽象的语法树。
- Flyweight:如何在抽象语法树中共享终结符。
- Iterator:解释器可用一个迭代器遍历该结构。
- Visitor:可用来在一个类中维护抽象语法树中的各节点的行为。如果经常要创建一种新的解释器,那么使用Visitor模式将解释放入一个独立的“访问者”对象更好一些。