《设计模式》— 行为型模式 — 解释器模式

《设计模式》— 行为型模式 — 解释器模式

  • 一、动机
  • 二、适用性
  • 三、结构
  • 四、参与者
    • 1、AbstractExpression
    • 2、TerminalExpression(终结符表达式)
    • 3、NonterminalExpression(非终结符表达式)
    • 4、Context
    • 5、Client
  • 五、效果
    • 1、易于改变和扩展问法
    • 2、易于实现文法
    • 3、负责的文法难以维护
    • 4、增加了新的解释表达式的方式
  • 六、实现
    • 1、创建抽象语法树
    • 2、定义解释操作
    • 3、与 Flyweight 模式共享终结符

一、动机

如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语句中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。

例如,搜索匹配一个模式的字符串是一个常见问题。正则表达式是描述字符串模式的一种标准语言。与其为每一个模式都构造一个特定的算法,不如使用一种通用的搜索算法来解释执行一个正则表达式,该正则表达式定义了待匹配字符串的集合。

解释器模式描述了如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如何解释这些句子。在上面的例子中,本设计模式描述了如何为正则表达式定义一个文法,如何表示一个特定的正则表达式,以及如何解释这个正则表达式。

考虑以下文法定义正则表达式:

expression ::= literal | alternation | repetition | '('expression')'
alternation ::= expression '|' expression
sequence ::= expression '&' expression
repetition ::= expressioon '*'
literal ::= 'a' | 'b' | 'c' | ... { 'a' | 'b' | 'c' | ... }*

符号 expression 是开始符号,literal 是定义简单字的终结符。

解释器模式实用类来表示每一条文法规则。规则右边的符号是这些类的实例变量。上面的文法用五个类表示:一个抽象类 RegularExpression 以及它的四哥子类 LiteralExpressionAlternativeExpressionSequenceExpressionRepetitionExpression,后三个类定义的变量代表子表达式。
《设计模式》— 行为型模式 — 解释器模式_第1张图片
每个用这个文法定义的正则表达式都表示为一个有这些类的实力构成的抽象语法树。例如,下面的抽象语法树
《设计模式》— 行为型模式 — 解释器模式_第2张图片
表示正则表达式

raining & (dogs | cats)*

如果我们为 RegularExpression 的每一个子类都定义 interpret 操作,那么就得到了这些正则表达式的一个解释器。解释器将该表达式的上下文作为一个参数。上下文包含输入字符串和关于目前它已有多少被匹配等信息。未匹配输入字符串的下一个部分,每一 RegularExpression 的子类都在当前上下文的基础上实现 interpret 操作。

二、适用性

当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好:

  • 文法简单。对于复杂的文法,文法的类层次变得庞大而无法管理。此时语法分析程序生成器这样的工具是更好的选择。它们无须构建抽象语法树即可解释表达式,这样可以节省空间而且还可能节省时间。
  • 效率不是关键问题。最高效的解释器通常不是通过直接解释语法分析树实现的,而是首相将他们转换成另一种形式。例如,正则表达式通常被转换成状态机。但即使在这种情况下,转换器也可用解释器模式实现,该模式仍是有用的。

三、结构

《设计模式》— 行为型模式 — 解释器模式_第3张图片

四、参与者

1、AbstractExpression

声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。

2、TerminalExpression(终结符表达式)

  • 实现与文法中的终结符相关联的解释操作。
  • 一个句子中的每个终结符需要该类的一个实例。

3、NonterminalExpression(非终结符表达式)

  • 对文法中的每一条规则都需要该类的一个实例。
  • 为非终结符实现解释操作。该操作一般要递归调用各子表达式对象的解释操作。

4、Context

全局信息

5、Client

构建抽象语法树和调用解释操作

五、效果

1、易于改变和扩展问法

因为该模式实用类来表示文法规则,你可以使用继承来改变或扩展该语法。已有的表达式可被增量式地改变,而新的表达式可定义为旧表达式的变体。

2、易于实现文法

定义抽象语法树中各个节点的类的实现大体类似。这些类易于直接编写,通常他们也可用一个编译器或语法分析程序生成器自动生成。

3、负责的文法难以维护

解释器模式为文法中的每一条规则至少定义了一个类,因此包含许多规则的文法可能难以管理和维护。可应用其他的设计模式来缓解这一问题。但当文法非常复杂时,其他的技术如语法分析程序或编译器生成器更为合适。

4、增加了新的解释表达式的方式

解释器模式使得实现新表达式“计算”变得容易。例如,你可以在表达式类上定义一个新的操作以支持优美打印或表达式的类型检查。我们可以使用 Visitor 模式来实现这些扩展功能。

六、实现

1、创建抽象语法树

解释器模式并未解释如何创建一个抽象的语法树。换言之,它不涉及语法分析。抽象语法树可用一个表驱动的语法分析程序来生成,也可用手写的语法分析程序创建,或直接由 Client 提供。

2、定义解释操作

并不一定要在表达式类中定义解释操作。如果经常要创建一种新的解释器,那么使用访问者模式可能更好一些。

3、与 Flyweight 模式共享终结符

在一些文法中,一个句子可能多次出现同一个终结符。此时最好共享那个符号的单个拷贝。计算机程序的文法是很好的例子 —— 每个程序变量在整个代码中间会出现多次。

终结节点通常不存储关于它们在抽象语法树中位置的信息。在解释过程中,任何它们所需要的上下文信息都由父节点传递给它们。因此共享的内部状态和传入的外部状态就区分的很明确,因此适合使用享元模式。

你可能感兴趣的:(读书笔记,#,《设计模式》,解释器模式,开发语言,设计模式,正则表达式)