5.3 INTERPRETER(解释器)—类行为型模式

1 意图

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

2 动机

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

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

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


image.png

解释器模式使用类来表示每一条文法规则,在规则右边的符号是这些类的实例变量。上面的文法用5个类表示,一个抽象类RegularExpression和它的四个子类LiteralExpression、AlternationExpression、SequenceExpression和RepetitionExpression后三个类定义的变量代表子表达式。


image.png

每个用这个文法定义的正则表达式都被表示为一个由这些类的实例构成的抽象语法树。
例如, 抽象语法树:
image.png

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

  • LiteralExpression将检查输入是否匹配它定义的字 ( literal );
  • AlternationExpression将检查输入是否匹配它的任意一个选择项;
  • RepetitionExpression将检查输入是否含有多个它所重复的表达式。
3 适用性

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

  • 该文法简单对于复杂的文法 , 文法的类层次变得庞大而无法管理。此时语法分析程序生
    成器这样的工具是更好的选择。它们无需构建抽象语法树即可解释表达式 , 这样可以节
    省空间而且还可能节省时间。
  • 效率不是一个关键问题最高效的解释器通常不是通过直接解释语法分析树实现的 , 而是
    首先将它们转换成另一种形式。例如,正则表达式通常被转换成状态机。但即使在这种
    情况下, 转换器仍可用解释器模式实现, 该模式仍是有用的。
4 结构
image.png
5 参与者
  • AbstractExpression(抽象表达式,如RegularExpression )
    ——声明一个抽象的解释操作,这个接口为抽象语法中所有的节点所共享;
  • TerminalExpression(终结符表达式,如LiteralExpression)
    ——实现与文法中的终结符相关联的解释操作;
    ——一个句子的每个终结符需要该类的一个实例。
  • NonterminalExpression (非终结符表达式,如AlternationExpression,RepetitionExpression,SequenceExpressions)
    ——对文法中的每一条规则 R ::= R1R2. . . Rn都需要一个NonterminalExpression类;
    ——为从R1到Rn的每个符号都维护一个AbstractExpression类型的实例变量;
    ——为文法中的非终结符实现解释 ( Interpret )操作。解释( Interpret )一般要递归地调用表示R1到Rn的那些对象的解释操作。
6 协作
  • Client构建(或被给定)一个句子,它是NonterminalExpression和TerminalExpression的实例装配而成。
6 协作
  • 1 Client构建(或被给定)一个句子,它是由NonterminalExpression和TerminalExpression的实例装配而成的一个抽象语法树,然后初始化上下文并调用解释操作。
  • 2 每一非终结符表达式节点定义相应表达式的解释操作,而各终极符表达式的解释操作构成了递归的基础。
  • 3 每一节点的解释操作通过上下文来存储和访问解释器的状态。
7 效果

解释器模式有下列的优点和不足:

  • 1 易于改变和扩展文法 因为该模式使用类来表示文法规则 , 你可使用继承来改变或扩展该文法。已有的表达式可被增量式地改变 ,而新的表达式可定义为旧表达式的变体。
  • 2 也易于实现文法 定义抽象语法树中各个节点的类的实现大体类似。这些类易于直接编写,通常它们也可以用一个编译器或语法分析程序生成器自动生成。
  • 3 复杂的文法难以维护 解释器模式为文法中的每一条规则至少定义了一个类,因此包含许多规则的文法可能难以管理和维护。可应用其它的设计模式来缓解这一问题。但当文法非常复杂时,其它技术如语法分析程序或编译生成器更为合适。
  • 4 增加了新的解释表达式的方式 解释器模式使得实现新表达式“计算”变得容易。 例如,你可以在表达式类上定义一个新的操作以支持优美打印或表达式的类型检查。如果你经常创建新的解释表达式的方式, 那么可以考虑使用Visitor(5.11)模式以避免修改这些代表文法的类。
8 实现

Interpreter和Composite(4 . 3)模式在实现上有许多相通的地方。下面是Interpreter所要考虑的一些特殊问题:

  • 1 创建抽象语法树解释器模式并未解释如何创建一个抽象的语法树。换言之 , 它不涉及语法分析。抽象语法树可用一个表驱动的语法分析程序来生成,也可用手写的 (通常为递归下降法) 语法分析程序创建,或直接由Client提供;
  • 2 定义解释操作 并不一定要在表达式类中定义解释操作。如果经常要创建一种新的解释器, 那么使用Visitor(5 . 11)模式将解释放入一个独立的 “访问者” 对象更好一些。例如,一个程序设计语言的会有许多在抽象语法树上的操作,比如类型检查、优化、代码生成,等等。恰当的做法是使用一个访问者以避免在每一个类上都定义这些操作。
  • 3 与Flyweight模式共享终结符 在一些文法中, 一个句子可能多次出现同一个终结符。此时最好共享那个符号的单个拷贝。计算机程序的文法是很好的例子 — 每个程序变量在整个代码中将会出现多次。在动机一节的例子中 , 一个句子中终结符dog (由LiteralExpression类描述)也可出现多次。终结节点通常不存储关于它们在抽象语法树中位置的信息。在解释过程中,任何它们所
    需要的上下文信息都由父节点传递给它们。因此在共享的 (内部的)状态和传入的(外部的)状态区分得很明确, 这就用到了Flyweight(4 . 6)模式。
9 代码示例

github地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容