天天看點

行為型模式之解釋器模式

在軟體開發中,會遇到有些問題多次重複出現,而且有一定的相似性和規律性。如果将它們歸納成一種簡單的語言,那麼這些問題執行個體将是該語言的一些句子,這樣就可以用“編譯原理”中的解釋器模式來實作了。

雖然使用解釋器模式的執行個體不是很多,但對于滿足以上特點,且對運作效率要求不是很高的應用執行個體,如果用解釋器模式來實作,其效果是非常好的,本文将介紹其工作原理與使用方法。

解釋器(Interpreter)模式的定義:給分析對象定義一個語言,并定義該語言的文法表示,再設計一個解析器來解釋語言中的句子。也就是說,用編譯語言的方式來分析應用中的執行個體。這種模式實作了文法表達式處理的接口,該接口解釋一個特定的上下文。

目錄

定義與特點

結構與實作

模式的結構

模式的實作

應用場景

擴充:Expression 表達式樹和Flee

這裡提到的文法和句子的概念同編譯原理中的描述相同,“文法”指語言的文法規則,而“句子”是語言集中的元素。例如,漢語中的句子有很多,“我是中國人”是其中的一個句子,可以用一棵文法樹來直覺地描述語言中的句子。

解釋器模式是一種類行為型模式,其主要優點如下:

擴充性好:由于在解釋器模式中使用類來表示語言的文法規則,是以可以通過繼承等機制來改變或擴充文法。

容易實作:在文法樹中的每個表達式節點類都是相似的,是以實作其文法較為容易。

解釋器模式的主要缺點如下:

執行效率較低:解釋器模式中通常使用大量的循環和遞歸調用,當要解釋的句子較複雜時,其運作速度很慢,且代碼的調試過程也比較麻煩。

會引起類膨脹:解釋器模式中的每條規則至少需要定義一個類,當包含的文法規則很多時,類的個數将急劇增加,導緻系統難以管理與維護。

可應用的場景比較少:在軟體開發中,需要定義語言文法的應用執行個體非常少,是以這種模式很少被使用到。

解釋器模式常用于對簡單語言的編譯或分析執行個體中,為了掌握好它的結構與實作,必須先了解編譯原理中的“文法、句子、文法樹”等相關概念。

文法:文法是用于描述語言的文法結構的形式規則。沒有規矩不成方圓,任何事情都要有規則,語言也一樣,不管它是機器語言還是自然語言,都有它自己的文法規則。例如,中文中的“句子”的文法如下:

注:這裡的符号“::=”表示“定義為”的意思,用“〈”和“〉”包覆的是非終結符,沒有包覆的是終結符。

句子:句子是語言的基本機關,是語言集中的一個元素,它由終結符構成,能由“文法”推導出。例如,上述文法可以推出“我是大學生”,是以它是句子。

文法樹:文法樹是句子結構的一種樹型表示,它代表了句子的推導結果,它有利于了解句子文法結構的層次。下圖所示是“我是大學生”的文法樹:

行為型模式之解釋器模式

有了以上基礎知識,現在來介紹解釋器模式的結構就簡單了。解釋器模式的結構與組合模式相似,不過其包含的組成元素比組合模式多,而且組合模式是對象結構型模式,而解釋器模式是類行為型模式。

解釋器模式包含以下主要角色:

抽象表達式(Abstract Expression)角色:定義解釋器的接口,約定解釋器的解釋操作,主要包含解釋方法 Interpret()。

終結符表達式(Terminal Expression)角色:是抽象表達式的子類,用來實作文法中與終結符相關的操作,文法中的每一個終結符都有一個具體終結表達式與之相對應。

非終結符表達式(Nonterminal Expression)角色:也是抽象表達式的子類,用來實作文法中與非終結符相關的操作,文法中的每條規則都對應于一個非終結符表達式。

環境(Context)角色:通常包含各個解釋器需要的資料或是公共的功能,一般用來傳遞被所有解釋器共享的資料,後面的解釋器可以從這裡擷取這些值。

用戶端(Client):主要任務是将需要分析的句子或表達式轉換成使用解釋器對象描述的抽象文法樹,然後調用解釋器的解釋方法,當然也可以通過環境角色間接通路解釋器的解釋方法。

解釋器模式的結構圖如圖所示:

行為型模式之解釋器模式

解釋器模式實作的關鍵是定義文法規則、設計終結符類與非終結符類、畫出結構圖,必要時建構文法樹,其代碼結構如下:

前面介紹了解釋器模式的結構與特點,下面分析它的應用場景:

當語言的文法較為簡單,且執行效率不是關鍵問題時。

當問題重複出現,且可以用一種簡單的語言來進行表達時。

當一個語言需要解釋執行,并且語言中的句子可以表示為一個抽象文法樹的時候,如 XML 文檔解釋。

注意:解釋器模式在實際的軟體開發中使用比較少,因為它會引起效率、性能以及維護等問題。如果碰到對表達式的解釋,在 C# 中可以用 Expression類 或 Flee 等來設計。

在項目開發中,如果要對資料表達式進行分析與計算,無須再用解釋器模式進行設計了,C# 提供了 Expression 表達式樹,也可以使用 Flee 等開源類庫,它們可以解釋一些複雜的文法,功能強大,使用簡單。

Flee是.NET架構的表達式解析器和評估器,它使用自定義編譯器,強類型表達式語言和輕量級代碼生成器将表達式直接編譯為IL。

github連結:Flee

使用說明:https://github.com/mparlak/Flee/wiki

使用NuGet安裝Flee,建立和評估表達式的示例代碼如下:

繼續閱讀