解释器模式

行为模式——解析器模式

1. 意图

        给定一个语言,定义它的文法的一种表示,并定义一个解析器,这个解析器使用该表示来解释语言中的句子。

2. 动机

        如果一种特定类型的问题的发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语句中的句子。这样就可以定义一个解析器,该解析器通过解释这些句子来解决该问题。
        举个实际的例子,带有参数的表达式求值。之后的例子就是语言的布尔类型求值。首先,需要定义一个表达式,比如(true and x) or (y and (not x)),随着x,y的值的改变,我们需要计算不同的值,当如,解释器不是编译器,像这种语法的解析,解析器依然不是首选的设计模式,毕竟我们需要构建语法书,定义语法,然后再简化语法,再根据语法编译出这类东西的编译器,形式比这个要复杂的多,因此,这东西就显得有点鸡肋。不过,设计模式本来就是学习思想而不是学习这种模式的具体作用,存在即是合理。

3. 适用性

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

  1. 该语法简单。对于复杂的语法树,文法的类层次变得庞大而无法管理。此时语法分析程序生成器这样的工具时更高的选择。
  2. 效率不是一个关键问题。最高效的解析器通常不是直接解析语法分析书实现的,而是转化成另一种形式。
  3. 代码冗余很大。这可能是由于继承本身所带来的缺陷,一个特定的语法的都需要有一个类来支撑,当语法功能很多大的时候,解析器的代码极其多,而且绝大部分都存在重复。

4. 结构图

解释器模式_第1张图片

5. 参与者

  1. Context(上下文)
    —— 包含解析器之外的一些上下文或者全局信息。
  2. AbstractExpression
    —— 声明一个抽象的解析操作,这个接口为抽象语法树中所有的节点所共享。
  3. TerminalExpression
    —— 实现与文法中的终结符相关联的解析器操作。
    —— 一个句子中的每个终结符需要该类的一个实例。
  4. NormalminalExpression
    —— 对文法的每一条规则R::=R1R2R3R4…都需要有一个NorterminalExpression。
    —— 为文法中的非终结符实现解析操作。解释一般要递归地调用表示R1到Rn的那些对象的解析操作。

6. 协作

  1. Client构建一个句子它是AbstractExpression的一个实例,然后初始化上下文并调用解析操作。
  2. 每一个非终结符表达式节点定义相应子表达式的解释操作。而各终结符表达式的解析操作构成了递归的前提。
  3. 每一个节点的解析操作作用上下文来存储和访问解释器的状态。

7. 效果

  1. 易于改变和扩展文法。
  2. 易于实现。
  3. 复杂的文法难以维护。
  4. 增加了新的解释表达式的方法。

8. 实现

  1. 构建抽象语法树
  2. 定义解释操作。
  3. 与Flyweight模式共享终结符。

9. 代码示例

相关代码为解析Cpp的布尔类型的运算,相关代码在Github中:
https://github.com/VioletDream-SXZ/DesignPatterns/tree/master/BehaviorPattern
该项目的UML图如下:
解释器模式_第2张图片

参看文献

Erich Gamma,Richard Helm,Ralph Johnson,John Vissides.Design Patterns Elements of Reusable Object-Oriented Software[M].北京:机械工业出版社.2009:9.

你可能感兴趣的:(C++,设计模式)