大话设计模式二十五之解释器模式

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

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

因为匹配字符的需求在软件的很多地方都会使用,而且行为之间都非常类似,过去的做法是针对特定的需求,编写特定的函数,比如判断Email、匹配电话号码等等,与其为每一个特定需求都写一个算法函数,不如使用一种通用的搜索算法来解释执行一个正则表达式,该正则表达式定义了待匹配字符串的集合。而所谓的解释器模式,正则表达式就是它的一种应用。解释器为正则表达式定义了一个文法,如何表示一个特定的正则表达式,以及如何解释这个正则表达式。




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


TerminalExpression(终结符表达式),实现与文法中的终结符相关联的解释操作。实现抽象表达式中所要求的接口,主要是一个interpret()方法。文法中每一个终结符都有一个具体终结表达式与之对应。



NonterminalExpression(非终结符表达式),为文法中的非终结符实现解释操作。对文法中每一条规则R1、R2.....Rn都需要一个具体的非终结符表达式类。通过实现抽象表达式的interpret()方法实现解释操作。解释操作以递归方式调用上面所提到的代表R1、R2......Rn中各个符号的实例变量。



Context,包含解释器之外的一些全局信息





二、解释器模式的好处

解释器模式就是用‘迷你语言’来表现程序要解决的问题,以迷你语言写成‘迷你程序’来表现具体的问题。

当有一个语言需要解释执行,并且你可以将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。


用了解释器模式,就意味着可以很容易地改变和扩展文法,因为该模式使用类来表示文法规则,你可以使用继承来改变或扩展该文法。也比较容易实现文法,因为定义抽象语法树中给个节点的类的实现大体类似,这些类都易于直接编写。


解释器模式也有不足之处,解释器模式为文法中的每一条规则至少定义了一个类,因此包含许多规则的文法可能难以管理和维护。建议当文法非常复杂时,使用其他的技术如语法分析程序或编译器生成器来处理。


三、音乐解释器

‘O’表示音阶,‘O1’表示低音阶,‘O2’表示中音阶,‘O3’表示高音阶;‘P’表示休止符,‘CDEFGAB’表示‘Do-Re-Mi-Fa-So-La-Ti’;音符长度1表示一拍,2表示2拍,0.5表示半拍,0.25表示四分之一拍,以此类推;注意:所有的字母和数字都要用半角空格分开。例如上海滩的歌曲第一句,‘浪奔’,可以写成‘O 2 E 0.5 G 0.5 A 3 ’表示中音开始,演奏的是mi so la



为了只关注设计模式编程,而不是具体的播放实现,只需要用控制台根据事先编写的语句解释成简谱就成了。


四、音乐解释器实现










现在需要增加一个文法,就是演奏速度,要求是T代表速度,以毫秒为单位,‘T1000’表示每节拍一秒,‘T 500’表示没节拍半秒。

首先增加一个表达式的子类叫音速,然后再在客户端的分支判断中增加一个case分支就可以了。




但是在增加一个文法时,除了扩展一个类外,还改动了客户端,只要在客户端的switch那里用简单工厂加反射就可以做到不改动客户端了。其实这个例子是不能代表解释器模式的全貌的,因为它只有终结符表达式,而没有非终结符表达式的子类。

猜你喜欢

转载自blog.csdn.net/nicolelili1/article/details/80344787