C++设计模式之解释器模式
前言
那日,闲的无聊,上了一个在线编程学习网站;最近那个在线编程学习网站很火啊;之前,盖茨、扎克伯格等大人物都来宣传了,思想是人人都应该学习编程;我一想就这算怎么回事啊?这要是在中国,还让人活不?话题不扯开了,还是说我上了那个在线编程网站吧,首先是给你玩一个小游戏,激发你对编程的兴趣。游戏是这样的,网页上有一个编辑框,屏幕上有一只小狗,比如你在编辑框中输入这样的句子:down run 10;按下回车,这个时候,你就看到屏幕上的小狗向下跑动了10个方格大小的长度;你再输入up walk 5,按下回车,小狗就会向上走动5个方格大小的长度。确实是有点意思;但是,对于我这种已经不需要这种游戏来激起我学习兴趣的人来说,我更喜欢的是去考虑它是如何实现的,如何将我输入的一句话去控制小狗移动的。而这一切的一切都不得不说到今天总结的解释器模式了。
解释器模式
在GOF的《设计模式:可复用面向对象软件的基础》一书中对解释器模式是这样说的:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。
就如上面说的那个游戏,我输入up walk 5,我必须按照:移动方向+移动方式+移动距离这种格式输入我的指令,而这种格式的指令就是一种文法,只有按照了我定义的这种文法去输入,才能控制屏幕上的小狗去移动。当然了,我输入up walk 5,屏幕上的小狗肯定是听不懂的,它不知道我输入的是什么,这个时候需要怎么办?我需要一个工具去将我输入的内容翻译成小狗能听懂的东西,而这个工具就是定义中提到的解释器,解释器对我输入的指令进行解释,然后将解释得到的指令发送给屏幕上的小狗,小狗听懂了,就进行实际的移动。
我们在开发中经常用到的正则表达式也是这类问题的代表。我们有的时候需要去匹配电话号码、身份证号;我们不用为了每一种匹配都写一个特定的算法,我们可以为每一种匹配定义一种文法,然后去解释这种文法定义的句子就ok了。
文法规则和抽象语法树
上面对于解释器模式的定义中,提及到了一个词:文法。在使用代码实现解释器模式之前,是非常有必要去学习一下文法的概念,以及如何表示一个语言的文法规则。再拿上面的游戏这个例子进行说明,我可以定义以下五条文法:
expression ::= direction action distance | composite //表达式
composite ::= expression 'and' expression //复合表达式
direction ::= 'up' | 'down' | 'left' | 'right' //移动方向
action ::= 'move' | 'walk' //移动方式
distance ::= an integer //移动距离
上面的5条文法规则,对应5个语言单位,这些语言单位可以分为两大类:一类为终结符(也叫做终结符表达式),例如上面的direction、action和distance,它们是语言的最小组成单位,不能再进行拆分;另一类为非终结符(也叫做非终结符表达式),例如上面的expression和composite,它们都是一个完整的句子,包含一系列终结符或非终结符。
我们就是根据上面定义的一些文法可以构成更多复杂的语句,计算机程序将根据这些语句进行某种操作;而我们这里列出的文法,计算机是无法直接看懂的,所以,我们需要对我们定义的文法进行解释;就好比,我们编写的C++代码,计算机是看不懂的,我们需要进行编译一样。解释器模式,就提供一种模式去给计算机解释我们定义的文法,让计算机根据我们的文法去进行工作。
在文法规则定义中可以使用一些符号来表示不同的含义,如使用“|”表示或,使用“{”和“}”表示组合,使用“*”表示出现0次或多次等,其中使用频率最高的符号是表示“或”关系的“|”,如文法规则“bool Value ::= 0 | 1”表示终结符表达式bool Value的取值可以为0或者1。
除了使用文法规则来定义一个语言,在解释器模式中还可以通过一种称之为抽象语法树的图形方式来直观地表示语言的构成,每一棵语法树对应一个语言实例,对于上面的游戏文法规则,可以通过以下的抽象语法树来进行表示:
- 上一篇:C++中的RTTI机制详解
- 下一篇:C++短路求值(逻辑与、逻辑或)实例