ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、视频、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 深度模式-解释器模式(Interpreter) ## **模式的定义与特点** 给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。 > 这里提到的文法和句子的概念同编译原理中的描述相同,“文法”指语言的语法规则,而“句子”是语言集中的元素。例如,汉语中的句子有很多,“我是中国人”是其中的一个句子,可以用一棵语法树来直观地描述语言中的句子。 角色: 环境角色(PlayContent):定义解释规则的全局信息。 抽象解释器(Empress):定义了部分解释具体实现,封装了一些由具体解释器实现的接口。 具体解释器(MusicNote):实现抽象解释器的接口,进行具体的解释执行。 定义语言的文法,并建立一个解释器解释该语言中的句子。每个用过 字典的童鞋都懂滴。 **好处:** 1. 扩展性好,灵活性大 。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。 2. 容易实现。在语法树中的每个表达式节点类都是相似的,所以实现其文法较为容易。 **弊端:** 可能难以维护复杂的文法 1. 执行效率较低。解释器模式中通常使用大量的循环和递归调用,当要解释的句子较复杂时,其运行速度很慢,且代码的调试过程也比较麻烦。 2. 会引起类膨胀。解释器模式中的每条规则至少需要定义一个类,当包含的文法规则很多时,类的个数将急剧增加,导致系统**难以管理与维护**。 3. 可应用的场景比较少。在软件开发中,需要定义语言文法的应用实例非常少,所以这种模式很少被使用到。 **应用场景:** 1. 当语言的文法较为简单,且执行效率不是关键问题时。 2. 当问题重复出现,且可以用一种简单的语言来进行表达时。 3. 当一个语言需要解释执行,并且语言中的句子可以表示为一个抽象语法树的时候,如 XML 文档解释。 4. 用于成对或者一对多的需求中 ## **模式的结构** 1. 抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。 2. 终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。 3. 非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。 4. 环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。 5. 客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。 解释器模式的结构图如图 ![](https://img.kancloud.cn/09/20/09204895da7ab5ad3b6f18caf1c5a0f9_710x349.png) ``` <pre class="calibre10">``` <span class="token">//抽象表达式类</span> interface <span class="token4">AbstractExpression</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">interpret</span><span class="token3">(</span>String $info<span class="token3">)</span><span class="token3">;</span> <span class="token">//解释方法</span> <span class="token3">}</span> <span class="token">//终结符表达式类</span> class <span class="token4">TerminalExpression</span> implements <span class="token4">AbstractExpression</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">interpret</span><span class="token3">(</span>String $info<span class="token3">)</span> <span class="token3">{</span> <span class="token">//对终结符表达式的处理</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//非终结符表达式类</span> class <span class="token4">NonterminalExpression</span> implements <span class="token4">AbstractExpression</span> <span class="token3">{</span> <span class="token">//exp: AbstractExpression</span> private $exp1<span class="token3">;</span> private $exp2<span class="token3">;</span> public <span class="token5">function</span> <span class="token4">interpret</span><span class="token3">(</span>String $info<span class="token3">)</span> <span class="token3">{</span> <span class="token">//非对终结符表达式的处理</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//环境类</span> class <span class="token4">Context</span> <span class="token3">{</span> private $exp<span class="token3">;</span> public <span class="token5">function</span> <span class="token4">__construct</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> <span class="token">//数据初始化</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">operation</span><span class="token3">(</span>String $info<span class="token3">)</span> <span class="token3">{</span> <span class="token">//调用相关表达式类的解释方法</span> <span class="token3">}</span> <span class="token3">}</span> ``` ``` 例子:“韶粵通”公交车卡的读卡器程序,韶关或者广州的老人、妇女、儿童免费,其余2元 ![](https://img.kancloud.cn/99/ed/99ed73820e00fdd9a8c77183fc1bc430_731x374.png) 文法规则: ``` <pre class="calibre10">``` <span class="token1"><</span>expression<span class="token1">></span> <span class="token3">:</span><span class="token3">:</span><span class="token1">=</span> <span class="token1"><</span>city<span class="token1">></span>的<span class="token1"><</span>person<span class="token1">></span> <span class="token1"><</span>city<span class="token1">></span> <span class="token3">:</span><span class="token3">:</span><span class="token1">=</span> 韶关<span class="token1">|</span>广州 <span class="token1"><</span>person<span class="token1">></span> <span class="token3">:</span><span class="token3">:</span><span class="token1">=</span> 老人<span class="token1">|</span>妇女<span class="token1">|</span>儿童 ``` ``` 代码 ``` <pre class="calibre10">``` <span class="token">//抽象表达式类</span> interface <span class="token4">Expression</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">interpret</span><span class="token3">(</span>String $info<span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token">//终结符表达式类</span> class <span class="token4">TerminalExpression</span> implements <span class="token4">Expression</span> <span class="token3">{</span> private $set<span class="token1">=</span><span class="token4">array</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> public <span class="token5">function</span> <span class="token4">__construct</span><span class="token3">(</span>array $data<span class="token3">)</span> <span class="token3">{</span> foreach <span class="token3">(</span>$data as $key <span class="token1">=</span><span class="token1">></span> $value<span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>set<span class="token3">[</span><span class="token3">]</span><span class="token1">=</span>$data<span class="token3">[</span>$key<span class="token3">]</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">interpret</span><span class="token3">(</span>String $info<span class="token3">)</span> <span class="token3">{</span> <span class="token5">if</span><span class="token3">(</span><span class="token4">in_array</span><span class="token3">(</span>$info<span class="token3">,</span> $this<span class="token1">-</span><span class="token1">></span>set<span class="token3">)</span><span class="token3">)</span> <span class="token3">{</span> <span class="token5">return</span> <span class="token6">true</span><span class="token3">;</span> <span class="token3">}</span> <span class="token5">return</span> <span class="token6">false</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//非终结符表达式类</span> class <span class="token4">AndExpression</span> implements <span class="token4">Expression</span> <span class="token3">{</span> private $city<span class="token1">=</span><span class="token5">null</span><span class="token3">;</span><span class="token">//Expression </span> private $person<span class="token1">=</span><span class="token5">null</span><span class="token3">;</span><span class="token">//Expression</span> public <span class="token5">function</span> <span class="token4">__construct</span><span class="token3">(</span>Expression $city<span class="token3">,</span>Expression $person<span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>city<span class="token1">=</span>$city<span class="token3">;</span> $this<span class="token1">-</span><span class="token1">></span>person<span class="token1">=</span>$person<span class="token3">;</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">interpret</span><span class="token3">(</span>String $info<span class="token3">)</span> <span class="token3">{</span> $s<span class="token1">=</span><span class="token4">explode</span><span class="token3">(</span><span class="token2">'的'</span><span class="token3">,</span>$info<span class="token3">)</span><span class="token3">;</span> <span class="token5">return</span> $this<span class="token1">-</span><span class="token1">></span>city<span class="token1">-</span><span class="token1">></span><span class="token4">interpret</span><span class="token3">(</span>$s<span class="token3">[</span><span class="token6">0</span><span class="token3">]</span><span class="token3">)</span> <span class="token1">&&</span> $this<span class="token1">-</span><span class="token1">></span>person<span class="token1">-</span><span class="token1">></span><span class="token4">interpret</span><span class="token3">(</span>$s<span class="token3">[</span><span class="token6">1</span><span class="token3">]</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//环境类</span> class <span class="token4">Context</span> <span class="token3">{</span> private $citys<span class="token1">=</span><span class="token4">array</span><span class="token3">(</span><span class="token2">"韶关"</span><span class="token3">,</span><span class="token2">"广州"</span><span class="token3">)</span><span class="token3">;</span> private $persons<span class="token1">=</span><span class="token4">array</span><span class="token3">(</span><span class="token2">"老人"</span><span class="token3">,</span><span class="token2">"妇女"</span><span class="token3">,</span><span class="token2">"儿童"</span><span class="token3">)</span><span class="token3">;</span> private $cityPerson<span class="token3">;</span><span class="token">//Expression</span> public <span class="token5">function</span> <span class="token4">__construct</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> $city <span class="token1">=</span> <span class="token5">new</span> <span class="token4">TerminalExpression</span><span class="token3">(</span>$this<span class="token1">-</span><span class="token1">></span>citys<span class="token3">)</span><span class="token3">;</span> $person <span class="token1">=</span> <span class="token5">new</span> <span class="token4">TerminalExpression</span><span class="token3">(</span>$this<span class="token1">-</span><span class="token1">></span>persons<span class="token3">)</span><span class="token3">;</span> $this<span class="token1">-</span><span class="token1">></span>cityPerson <span class="token1">=</span> <span class="token5">new</span> <span class="token4">AndExpression</span><span class="token3">(</span>$city<span class="token3">,</span>$person<span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">freeRide</span><span class="token3">(</span>String $info<span class="token3">)</span> <span class="token3">{</span> $ok<span class="token1">=</span>$this<span class="token1">-</span><span class="token1">></span>cityPerson<span class="token1">-</span><span class="token1">></span><span class="token4">interpret</span><span class="token3">(</span>$info<span class="token3">)</span><span class="token3">;</span><span class="token">//"韶关的老人"</span> <span class="token5">if</span><span class="token3">(</span>$ok<span class="token3">)</span><span class="token3">{</span> <span class="token4">print_r</span><span class="token3">(</span><span class="token2">"您是"</span><span class="token3">.</span>$info<span class="token3">.</span><span class="token2">",您本次乘车免费!"</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token5">else</span> <span class="token3">{</span> <span class="token4">print_r</span><span class="token3">(</span>$info<span class="token3">.</span><span class="token2">",您不是免费人员,本次乘车扣费2元!"</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">InterpreterPatternDemo</span> <span class="token3">{</span> public static <span class="token5">function</span> <span class="token4">main</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> $bus<span class="token1">=</span><span class="token5">new</span> <span class="token4">Context</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $bus<span class="token1">-</span><span class="token1">></span><span class="token4">freeRide</span><span class="token3">(</span><span class="token2">"韶关的老人"</span><span class="token3">)</span><span class="token3">;</span> $bus<span class="token1">-</span><span class="token1">></span><span class="token4">freeRide</span><span class="token3">(</span><span class="token2">"韶关的年轻人"</span><span class="token3">)</span><span class="token3">;</span> $bus<span class="token1">-</span><span class="token1">></span><span class="token4">freeRide</span><span class="token3">(</span><span class="token2">"广州的妇女"</span><span class="token3">)</span><span class="token3">;</span> $bus<span class="token1">-</span><span class="token1">></span><span class="token4">freeRide</span><span class="token3">(</span><span class="token2">"广州的儿童"</span><span class="token3">)</span><span class="token3">;</span> $bus<span class="token1">-</span><span class="token1">></span><span class="token4">freeRide</span><span class="token3">(</span><span class="token2">"山东的儿童"</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> InterpreterPatternDemo<span class="token3">:</span><span class="token3">:</span><span class="token4">main</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> ``` ``` 例子2 ``` <pre class="calibre17">``` class <span class="token4">Expression</span> <span class="token3">{</span> <span class="token">//抽象表示</span> <span class="token5">function</span> <span class="token4">interpreter</span><span class="token3">(</span>$str<span class="token3">)</span> <span class="token3">{</span> <span class="token5">return</span> $str<span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">ExpressionNum</span> extends <span class="token4">Expression</span> <span class="token3">{</span> <span class="token">//表示数字</span> <span class="token5">function</span> <span class="token4">interpreter</span><span class="token3">(</span>$str<span class="token3">)</span> <span class="token3">{</span> <span class="token4">switch</span><span class="token3">(</span>$str<span class="token3">)</span> <span class="token3">{</span> case <span class="token2">"0"</span><span class="token3">:</span> <span class="token5">return</span> <span class="token2">"零"</span><span class="token3">;</span> case <span class="token2">"1"</span><span class="token3">:</span> <span class="token5">return</span> <span class="token2">"一"</span><span class="token3">;</span> case <span class="token2">"2"</span><span class="token3">:</span> <span class="token5">return</span> <span class="token2">"二"</span><span class="token3">;</span> case <span class="token2">"3"</span><span class="token3">:</span> <span class="token5">return</span> <span class="token2">"三"</span><span class="token3">;</span> case <span class="token2">"4"</span><span class="token3">:</span> <span class="token5">return</span> <span class="token2">"四"</span><span class="token3">;</span> case <span class="token2">"5"</span><span class="token3">:</span> <span class="token5">return</span> <span class="token2">"五"</span><span class="token3">;</span> case <span class="token2">"6"</span><span class="token3">:</span> <span class="token5">return</span> <span class="token2">"六"</span><span class="token3">;</span> case <span class="token2">"7"</span><span class="token3">:</span> <span class="token5">return</span> <span class="token2">"七"</span><span class="token3">;</span> case <span class="token2">"8"</span><span class="token3">:</span> <span class="token5">return</span> <span class="token2">"八"</span><span class="token3">;</span> case <span class="token2">"9"</span><span class="token3">:</span> <span class="token5">return</span> <span class="token2">"九"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">ExpressionCharater</span> extends <span class="token4">Expression</span> <span class="token3">{</span> <span class="token">//表示字符</span> <span class="token5">function</span> <span class="token4">interpreter</span><span class="token3">(</span>$str<span class="token3">)</span> <span class="token3">{</span> <span class="token5">return</span> <span class="token4">strtoupper</span><span class="token3">(</span>$str<span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">Interpreter</span> <span class="token3">{</span> <span class="token">//解释器</span> <span class="token5">function</span> <span class="token4">execute</span><span class="token3">(</span>$string<span class="token3">)</span> <span class="token3">{</span> $expression <span class="token1">=</span> <span class="token5">null</span><span class="token3">;</span> <span class="token5">for</span><span class="token3">(</span>$i <span class="token1">=</span> <span class="token6">0</span><span class="token3">;</span>$i<span class="token1"><</span><span class="token4">strlen</span><span class="token3">(</span>$string<span class="token3">)</span><span class="token3">;</span>$i<span class="token1">++</span><span class="token3">)</span> <span class="token3">{</span> $temp <span class="token1">=</span> $string<span class="token3">[</span>$i<span class="token3">]</span><span class="token3">;</span> <span class="token4">switch</span><span class="token3">(</span><span class="token6">true</span><span class="token3">)</span> <span class="token3">{</span> case <span class="token4">is_numeric</span><span class="token3">(</span>$temp<span class="token3">)</span><span class="token3">:</span> $expression <span class="token1">=</span> <span class="token5">new</span> <span class="token4">ExpressionNum</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token5">break</span><span class="token3">;</span> default<span class="token3">:</span> $expression <span class="token1">=</span> <span class="token5">new</span> <span class="token4">ExpressionCharater</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> echo $expression<span class="token1">-</span><span class="token1">></span><span class="token4">interpreter</span><span class="token3">(</span>$temp<span class="token3">)</span><span class="token3">;</span> echo <span class="token2">"<br>"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//client</span> $obj <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Interpreter</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $obj<span class="token1">-</span><span class="token1">></span><span class="token4">execute</span><span class="token3">(</span><span class="token2">"123s45abc"</span><span class="token3">)</span><span class="token3">;</span> <span class="token">/* 输出: 一 二 三 S 四 五 A B C */</span> ``` ```