关于解释器模式,我在网上转了两三圈,心中有了那么一点概念 ,也不知道本身理解的是对仍是错。html
其实关于每一种设计模式,我总想找出一个答案,那就是为何要用这种设计模式, 若是不用会怎么样,会致使什么后果?python
我想只有搞懂了这个答案,我才有可能会学明白,才能给出实例。正则表达式
下面开始落笔,沉淀出我对解释器模式的印象。express
这都是从下面的连接里面摘的,我感受利于我理解,我就放在博客里。编程
为人处事是一门大学问,察言观色、听懂弦外之音都是很是重要的。设计模式
老板跟你说“XX你最近表现平平啊,还得要多努力”,数据结构
若是你不当回事,日常对待,可能下次就是“XX,恩,你人仍是不错,日常工做也很努力,可是我想这份工做可能不是很适合你…..”。app
又好比你老大说“XX,你最近表现不错,工做积极性很高啊!继续保持啊!”,编程语言
你高兴乐呵着心想是否是老板要给我加工资了,可能你等到花都谢了也没有,获得的可能会是更多的工做量。工具
对于咱们刚刚入社会的人不够圆滑,不会察言观色,更听不懂老板的弦外之音,因此咱们期待若是有一个翻译机该多好,直接将别人的弦外之音给翻译出来就行了。
在咱们实际的生活中是这样,在软件的世界里也一样存在着翻译机,只不过在软件中咱们称之为解释器。在系统中若是某一特定类型的问题在频繁的发生,此时咱们就有必要将这些问题的实例表述为一个语言中句子,所以能够构建一个解释器,而后利用该解释器来解释这些句子来解决这些问题。
对每一个应用来讲,至少有如下两种不一样的用户分类。
1] 基本用户:这类用户只但愿可以凭直觉使用应用。他们不喜欢花太多时间配置或学习应用的内部。对他们来讲,基本的用法就足够了。
2] 高级用户:这些用户,实际上一般是少数,不介意花费额外的时间学习如何使用应用的高级特性。若是知道学会以后能获得如下好处,他们甚至会去学习一种配置(或脚本)语言。
a]可以更好地控制一个应用
b]以更好的方式表达想法
c]提升生产力
解释器(Interpreter)模式仅能引发应用的高级用户的兴趣。这是由于解释器模式背后的主要思想是让非初级用户和领域专家使用一门简单的语言来表达想种简单的语言法。然而,什么是一种简单的语言?对于咱们的需求来讲,一就是没编程语言那么复杂的语言。
通常而言,咱们想要建立的是一种领域特定语言(Domain Specific Language,DSL)。DSL是一种针对一个特定领域的有限表达能力的计算机语言。不少不一样的事情都使用DSL,好比,战斗模拟、记帐、可视化、配置、通讯协议等。DSL分为内部DSL和外部DSL。
内部DSL构建在一种宿主编程语言之上。内部DSL的一个例子是,使用Python解决线性方程组的一种语言。使用内部DSL的优点是咱们没必要担忧建立、编译及解析语法,由于这些已经被宿主语言解决掉了。劣势是会受限于宿主语言的特性。若是宿主语言不具有这些特性,构建一种表达能力强、简洁并且优美的内部DSL是富有挑战性的。
外部DSL不依赖某种宿主语言。DSL的建立者能够决定语言的方方面面(语法、句法等),但也要负责为其建立一个解析器和编译器。为一种新语言建立解析器和编译器是一个很是复杂、长期而又痛苦的过程。
解释器模式仅与内部DSL相关。所以,咱们的目标是使用宿主语言提供的特性构建一种简单但有用的语言,在这里,宿主语言是Python。注意,解释器根本不处理语言解析,它假设咱们已经有某种便利形式的解析好的数据,能够是抽象语法树(abstract syntax tree,AST)或任何其余好用的数据结构。
所谓解释器(Interpreter)就是将一系列指令转化成代码,可以执行的代码。Interpreter原本就有翻译的意思。
GoF给它的定义是:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
这很像命令模式,可是命令模式的命令必须是实现了Command的类的实例,而解释器模式的命令则能够是任何对象,如字符串,整数等,只要解释器能将其解释成具体行为就行。
虽然目前计算机编程语言有好几百种,但有时人们仍是但愿用一些简单的语言来实现特定的操做,只须要向计算机输入一个句子或文件,就能按照预约的文法规则来对句子或文件进行解释。例如,咱们想要只输入一个加法/减法表达式,它就可以计算出表达式结果。例如输入“1+2+3-4+1”时,将输出计算结果为3。像C++,Java或C#都没法直接解释相似这样的字符串,所以用户必须自定义一套文法规则来实现对这些语句的解释,即设计一个自定义语言。若是所基于的编程语言是面向对象语言,此时可使用解释器模式实现自定义语言。
1]第一个能想到的利用解释器模式的程序应该就是编译器了,编译器能将源代码翻译成机器能认识的机器码,这是很典型的解释器模式。
2]另外正则表达式(RegExp)也是解释器模式的一个应用。
其它的领域使用解释器模式是极少的,使用极其有限,另外有了yacc和lex等语法分析工具后使用解释器模式的地方就更少了。
1]易于改变和扩展文法 => 经过继承来改变或扩展
2]增长新的解释表达式较为方便 => 只需对应新增一个新的终结符或非终结符表达式,原有代码无须修改,符合开闭原则!
执行效率较低。解释器模式中一般使用大量的循环和递归调用,当要解释的句子较复杂时,其运行速度很慢,且代码的调试过程也比较麻烦。
会引发类膨胀。解释器模式中的每条规则至少须要定义一个类,当包含的文法规则不少时,类的个数将急剧增长,致使系统难以管理与维护。
可应用的场景比较少。在软件开发中,须要定义语言文法的应用实例很是少,因此这种模式不多被使用到。
在软件开发中,会遇到有些问题屡次重复出现,并且有必定的类似性和规律性。
其余几乎用不到
Context:上下文环境,包含解释器以外的全局信息
Client:客户端,解析表达式,构建语法树,执行具体的解释操做等
AbstractExpression:抽象表达式,声明一个抽象的解释操做弗雷,并定义一个抽象的解释方案,其具体的实如今各个具体的子类解释器中完成。
TerminalExpression:终结符表达式,实现文法中终结符有关的解释操做。文法中每个终结符都有一个具体的终结表达式与之对应。
NonterminalExpression:非终结表达式,实现文法中非终结符有关的解释操做。
其中AbstractExpression的interpret()是抽象的解析方法,参数是上下文的环境,而interpret()方法的具体实现则由TerminalExpression和NonterminalExpression实现。
from abc import ABCMeta, abstractmethod class AbstractExpression(): """ 抽象表达式类,声明一个抽象的解释操做,这个接口为抽象语法树中全部的节点所共享 """ __metaclass__ = ABCMeta @abstractmethod def interpret(self, context): pass class TerminalExpression(AbstractExpression): """ 终结符表达式,实现与文法中的终结符相关联的解释操做。实现抽象表达式中所要求的接口,主要是一个interpret()方法。 文法中的每个终结符都有一个具体终结符表达式与之相对应。 """ def interpret(self, context): print("终结符表达式") class NontermialExpression(AbstractExpression): """ 非终结符表达式,为文法中的非终结符实现解释操做。对文法中每一条规则R1,R2,...Rn都须要一个具体的非终结符表达式类。 经过实现抽闲表达式的interpret()方法实现解释操做。解释操做以递归的方式调用上 main所提到的表明R1,R2,...Rn中各 个符号的实例变量。 """ def interpret(self, context): print("非终结符表达式") class Context(): """ 上下文类,包含解释器以外的一些全局信息 """ def __init__(self): self.input = None self.output = None def main(): """ 客户端代码,构建表示该文法定义的语言中一个特定的句子的抽象语法树。 """ context = Context() exp_list = [] exp_list.append(TerminalExpression()) exp_list.append(NontermialExpression()) exp_list.append(TerminalExpression()) exp_list.append(NontermialExpression()) for exp in exp_list: exp.interpret(context) main()
class Variables(object): # Context def __init__(self): self._v = {} def put(self, variable, value: int): self._v[variable] = value def get(self, variable) -> int: return self._v.get(variable) class ArithmeticExpression(object): # AbstractExpression def interpret(self, variables) -> float: pass class Variable(ArithmeticExpression): # TerminalExpression def __init__(self, value: str): self.variable = value def interpret(self, variables): return variables.get(self.variable) class Plus(ArithmeticExpression): # NonTerminalExpression def __init__(self, left: ArithmeticExpression, right: ArithmeticExpression): self._left = left self._right = right def interpret(self, variables: Variables): return self._left.interpret(variables) + self._right.interpret(variables) class Substract(ArithmeticExpression): # NonTerminalExpression def __init__(self, left: ArithmeticExpression, right: ArithmeticExpression): self._left = left self._right = right def interpret(self, variables: Variables): return self._left.interpret(variables) - self._right.interpret(variables) class Multiply(ArithmeticExpression): # NonTerminalExpression def __init__(self, left: ArithmeticExpression, right: ArithmeticExpression): self._left = left self._right = right def interpret(self, variables: Variables): return self._left.interpret(variables) * self._right.interpret(variables) class Division(ArithmeticExpression): # NonTerminalExpression def __init__(self, left: ArithmeticExpression, right: ArithmeticExpression): self._left = left self._right = right def interpret(self, variables: Variables): return self._left.interpret(variables) / self._right.interpret(variables) class Calculator(object): def __init__(self, expression: str, context: Variables): self.expression = expression self.context = context self.value = None def get_value(self): self.calculate() return self.value def calculate(self): OP = ['+', '-', '*', '/', '(', ')', '='] priority = [ # 各运算符相遇时,优先级比较 1: 大于,2: 小于,3: 多弹一个符号 [1, 1, 2, 2, 2, 1, 1], [1, 1, 2, 2, 2, 1, 1], [1, 1, 1, 1, 2, 1, 1], [1, 1, 1, 1, 2, 1, 1], [2, 2, 2, 2, 2, 3, 0], [1, 1, 1, 1, 0, 1, 1], [2, 2, 2, 2, 2, 0, 3] ] opan = [] # 操做数 opat = ['='] # 操做符,初始带一个=为的是做为结束符使用 for char in self.expression: while True: if char not in OP: # 变量 opan.append(Variable(char)) break else: # 操做符 level = priority[OP.index(opat[-1::1][0])][OP.index(char)] if level == 1: op = opat.pop() b = opan.pop() a = opan.pop() if op == '+': opan.append(Plus(a, b)) elif op == '-': opan.append(Substract(a, b)) elif op == '*': opan.append(Multiply(a, b)) elif op == '/': opan.append(Division(a, b)) elif level == 2: opat.append(char) break elif level == 3: opat.pop() break else: break self.value = opan.pop().interpret(self.context) if __name__ == '__main__': variables = Variables() variables.put('a', 1) variables.put('b', 2) variables.put('c', 3) variables.put('d', 4) aa = Variable('a') bb = Variable('b') cc = Variable('c') dd = Variable('d') # (1-2)+(3*4) print(Plus(Substract(aa, bb), Multiply(cc, dd)).interpret(variables)) print(Calculator('a-b+c*d=', variables).get_value())
这是简书上的一个例子, https://www.jianshu.com/p/45153c25c29c
感谢做者
后面取priority 那块我也没太看懂,也不影响做为解释器模式的例子
这里就做参考
参考:
https://www.cnblogs.com/hujingnb/p/10171605.html
https://www.cnblogs.com/cbf4life/archive/2009/12/17/1626125.html
https://www.e-learn.cn/content/qita/708812
https://blog.csdn.net/hbu_pig/article/details/80808881
https://www.jianshu.com/p/d9365606fd8f
https://www.cnblogs.com/Siny0/p/11155954.html
https://www.cnblogs.com/imakoo/articles/2944578.html
https://www.cnblogs.com/chenssy/p/3679190.html
https://www.cnblogs.com/chenssy/p/3346427.html
https://www.cnblogs.com/edisonchou/p/7512733.html
https://www.jianshu.com/p/0e7e26bbe204
https://www.cnblogs.com/CheeseZH/p/9491324.html