天天看點

C#設計模式之二十三解釋器模式(Interpreter Pattern)【行為型】

一、引言

   今天我們開始講“行為型”設計模式的第十一個模式,也是面向對象設計模式的最後一個模式,先要說明一下,其實這個模式不是最後一個模式(按Gof的排序來講),為什麼把它放在最後呢?因為我們在業務系統中寫一個解釋器的機會并不是很多,實踐比較少,了解和應用該模式就有些困難,是以就放在最後來說。該模式就是【解釋器模式】,英文名稱是:Interpreter Pattern。按老規矩,先從名稱上來看看這個模式,個人的最初了解“解釋器”和Google的中英翻譯功能類似。如果有一天你去國外旅遊去了,比如去美國吧,美國人是講英語的,我們是講漢語的,如果英語聽不懂,講不好,估計溝通就完蛋了,不能溝通,估計玩的就很難盡興了,因為有很多景點的解說你可能不明白(沒有中文翻譯的情況下,一般情況會有的)。是以我們需要一個軟體,可以把中英文互譯,那彼此就可以更好的了解對方的意思,我感覺翻譯軟體也可以稱得上是解釋器,把你不懂的解釋成你能了解的。我們寫代碼,需要編譯器把我們寫的代碼編譯成機器可以了解的機器語言,從這方面來講,C#的編譯器也是一種解釋器。

二、解釋器模式的詳細介紹

2.1、動機(Motivate)

   在軟體建構過程中,如果某一特定領域的問題比較複雜,類似的模式不斷重複出現,如果使用普通的程式設計方式來實作将面臨非常頻繁的變化。在這種情況下,将特定領域的問題表達為某種文法規則下的句子,然後建構一個解釋器來解釋這樣的句子,進而達到解決問題的目的。

2.2、意圖(Intent)

   給定一個語言,定義它的文法的一種表示,并定義一種解釋器,這個解釋器使用該表示來解釋語言中的句子。                                      ——《設計模式》GoF

2.3、結構圖(Structure)

C#設計模式之二十三解釋器模式(Interpreter Pattern)【行為型】

2.4、模式的組成

    可以看出,在解釋器模式的結構圖有以下角色:

    (1)、抽象表達式(AbstractExpression):定義解釋器的接口,約定解釋器的解釋操作。其中的Interpret接口,正如其名字那樣,它是專門用來解釋該解釋器所要實作的功能。

    (2)、終結符表達式(Terminal Expression):實作了抽象表達式角色所要求的接口,主要是一個interpret()方法;文法中的每一個終結符都有一個具體終結表達式與之相對應。比如有一個簡單的公式R=R1+R2,在裡面R1和R2就是終結符,對應的解析R1和R2的解釋器就是終結符表達式。

    (3)、非終結符表達式(Nonterminal Expression):文法中的每一條規則都需要一個具體的非終結符表達式,非終結符表達式一般是文法中的運算符或者其他關鍵字,比如公式R=R1+R2中,“+”就是非終結符,解析“+”的解釋器就是一個非終結符表達式。

    (4)、環境角色(Context):這個角色的任務一般是用來存放文法中各個終結符所對應的具體值,比如R=R1+R2,我們給R1指派100,給R2指派200。這些資訊需要存放到環境角色中,很多情況下我們使用Map來充當環境角色就足夠了。

    (5)、用戶端(Client):指的是使用解釋器的用戶端,通常在這裡将按照語言的文法做的表達式轉換成使用解釋器對象描述的抽象文法樹,然後調用解釋操作。

2.5、解釋器模式的代碼實作

    在很多場合都需要把數字轉換成中文,我們就可以使用解釋器來實作該功能,把給定的數字解釋成符合文法規範的漢字表示法。實作代碼如下:

三、解釋器模式的實作要點:

       使用Interpreter模式來表示文法規則,進而可以使用面向對象技巧友善地“擴充”文法。

  Interpreter模式比較适合簡單的文法表示,對于複雜的文法表示,Interpreter模式會産生比較大的類層次結構,需要求助于文法分析生成器這樣的标準工具。

    (1)、解釋器模式的主要優點有:

        1】、易于改變和擴充文法。

        2】、每一條文法規則都可以表示為一個類,是以可以友善地實作一個簡單的語言。

        3】、實作文法較為容易。在抽象文法樹中每一個表達式節點類的實作方式都是相似的,這些類的代碼編寫都不會特别複雜,還可以通過一些工具自動生成節點類代碼。

        4】、增加新的解釋表達式較為友善。如果使用者需要增加新的解釋表達式隻需要對應增加一個新的終結符表達式或非終結符表達式類,原有表達式類代碼無須修改,符合“開閉原則”

 (2)、解釋器模式的主要缺點有:

        1】、對于複雜文法難以維護。在解釋器模式中,每一條規則至少需要定義一個類,是以如果一個語言包含太多文法規則,類的個數将會急劇增加,導緻系統難以管理和維護,此時可以考慮使用文法分析程式等方式來取代解釋器模式。

        2】、執行效率較低。由于在解釋器模式中使用了大量的循環和遞歸調用,是以在解釋較為複雜的句子時其速度很慢,而且代碼的調試過程也比較麻煩。

    (3)、在下面的情況下可以考慮使用解釋器模式:

        Interpreter模式的應用場合是Interpreter模式應用中的難點,隻有滿足“業務規則頻繁變化,且類似的模式不斷重複出現,并且容易抽象為文法規則的問題”才适合使用Interpreter模式。

        1】、當一個語言需要解釋執行,并可以将該語言中的句子表示為一個抽象文法樹的時候,可以考慮使用解釋器模式(如XML文檔解釋、正規表達式等領域)

        2】、一些重複出現的問題可以用一種簡單的語言來進行表達。

        3】、一個語言的文法較為簡單.

        4】、當執行效率不是關鍵和主要關心的問題時可考慮解釋器模式(注:高效的解釋器通常不是通過直接解釋抽象文法樹來實作的,而是需要将它們轉換成其他形式,使用解釋器模式的執行效率并不高。)

四、.NET 解釋器模式的實作

     正規表達式就是一個典型的解釋器。ASP.NET中,把aspx檔案轉化為dll時,會對html語言進行處理,這個處理過程也包含了解釋器的模式在裡面。Interpreter模式其實有Composite模式的影子,但它們解決的問題是不一樣的。

五、總結

    今天就寫到這裡了,23種設計模式都寫完了,有時間了,再寫一篇文章,為這個系列做一個總結,同時也做一個設計模式的目錄,友善大家浏覽和學習。解釋器模式可以和其他模式混合使用,具體的使用方法和解決的問題我列出了一個表,大家好好了解一下,或許對大家有些幫助。清單如下:

     (1)解釋器群組合模式

          這兩種可以組合使用,一般非終結符解釋器相當于組合模式中的組合對象,終結符解釋器相當于葉子對象。

     (2)解釋器模式和疊代器模式

          由于解釋器模式通常使用組合模式來實作,是以在周遊整個對象結構時,可以使用疊代器模式。

     (3)解釋器模式和享元模式

          在使用解釋器模式的時候,可能會造成多個細粒度對象,如各式各樣的終結符解釋器,而這些終結符解釋器對不同的表達式來說是一樣的,是可以共用的,是以可以引入享元模式來共享這些對象。

     (4)解釋器模式和通路者模式

         在解釋器模式中,文法規則和解釋器對象是有對應關系的。文法規則的變動意味着功能的變化。自然會導緻使用不同的解釋器對象;而且一個文法規由可以被不同的解釋器解釋執行。是以在建構抽象文法樹的時候,如果每個節點所對應的解釋器對象是固定的,這意味着該節點對應的功能是固定的,那麼就不得不根據需要來建構不同的抽象文法樹。為了讓建構的抽象文法樹較為通用,那就要求解釋器的功能不要那麼固定,要能很友善地改變解釋器的功能,這個時候就變成了如何能夠很友善地更改樹形結構中節點對象的功能了,通路者模式可以很好的實作這個功能。