1. 程式人生 > >直譯器模式( Interpreter Pattern ): 最不容易實現的設計模式

直譯器模式( Interpreter Pattern ): 最不容易實現的設計模式

  1. 參考書籍: 《Design Patterns: Elements of Reusable Object-Oriented Software》

設計模式用前須知

  • 設計模式種一句出現頻率非常高的話是,“ 在不改動。。。。的情況下, 實現。。。。的擴充套件“ 。
  • 對於設計模式的學習者來說,充分思考這句話其實非常重要, 因為這句往往只對框架/ 工具包的設計才有真正的意義。因為框架和工具包存在的意義,就是為了讓其他的程式設計師予以利用, 進行功能的擴充套件,而這種功能的擴充套件必須以不需要改動框架和工具包中程式碼為前提
  • 對於應用程式的編寫者, 從理論上來說, 所有的應用層級程式碼至少都是處於可編輯範圍內的, 如果不細加考量, 就盲目使用較為複雜的設計模式, 反而會得不償失, 畢竟靈活性的獲得, 也是有代價的。

直譯器模式(Interpreter Pattern)

  • 設計意圖
    • 給定一個語言後, 為該語言定義一種語法, 同時再定義一個直譯器, 該直譯器會按照定義的語法來解釋該語言中的語句。
  • GoF 舉例

    • 當一類問題經常反覆出現時, 那麼就可能值得去設計一個自定義的語言, 用於表達該問題, 並定義一個直譯器,理解自定義語言表達的問題並解決問題。 正則表示式就是一個很好的例子。 正則表示式是一種用於描述字串模式的標準語言。 與其為每種字串模式編寫特定的匹配演算法, 不如設計一種查詢演算法可以理解正則表示式, 按照正則表示式所描述的模式去匹配字串。
  • 解決方案

    • 直譯器模式描述瞭如何為一門簡單的語言定義語法, 如何表示該語言中的語句, 以及如何解釋這些語句。 在下面的這個例子中, 直譯器模式將會描述如何為正則表示式定義語法, 如何表示一個正則表示式, 以及如何解釋這個正則表示式。
    • 現在假設下列的語法定義了正則表示式。

      expression ::= literal | alternation | sequence | repetition |
      '(' expression ')'
      alternation ::= expression '|' expression
      sequence ::= expression '&'
      expression repetition ::= expression '*' literal ::= 'a' | 'b' | 'c' | ... { 'a' | 'b' | 'c' | ... }*
      • Tips: 上面的這種語法定義方式對於在大學時期學過編譯原理,或者翻看過編譯原理書籍的同志會比較熟悉。本例中, “::=”是定義符號,表示左側的東西被“定義為”右側的東西。 “ | ”表示“或”。“ & ”表示 “連線”
    • 直譯器模式會為每一條語法規則定義一個類來表示該語法規則。如下圖所示
      這裡寫圖片描述
    • 每一個按照該語法定義的正則表示式都會被一個由上述類例項構成的抽象語法樹, 例如 ,正則表示式 raining & (dogs | cats)* 就會被表示成下圖的結構。
      這裡寫圖片描述
    • 我們可以在這些 RegularExpression 的子類中實現 interpret() 方法 , 為這些表示式建立直譯器 。 每一個 RegularExpression 的子類的 Interpret 方法可以通過一個 Context 物件獲取它所需要的上下文資訊(待匹配的字串, 整個表示式到目前為止被匹配了多少), 例如
      • LiteralExpression 會檢查輸入是否符合 literal 的定義
      • AlternationExpression 會檢查輸入是否匹配 alternation1 , alternation2 中的任意一個表示式
      • RepeationExpression 會檢查輸入是否包含它所持有的例項 RegularExpression 的多個重複匹配。

應用場景

  • 直譯器模式的確是在描述如何實現一個語言的語法表達, 以及如何解釋它。 但直譯器模式最好是在如下情形使用:
    • 要定義的語言有較為簡單的語法。當語法比較複雜時, 用於表達語法的類的層級結構會變得很大且難以管理。此時, 去借助一些直譯器生成工具更為合適。
    • 應用對語言解釋的效率要求不苛刻。 最有效率的直譯器通常並不會以直接解析語法樹的方式去實現, 而是會首先將語法樹轉換為其它形式。 例如, 正在表示式通常會先被轉換成狀態機的模式, 但是即便如此, 這種轉換工具也可以用直譯器模式去實現, 所以直譯器模式在這個意義上, 依舊是適用的。

結構圖

這裡寫圖片描述

總結

  • 直譯器模式可能對於80%的程式設計師來說沒有什麼應用機會。原因是它在教你怎麼使用面向物件的語言來實現一些自定義的語言, 以及自定義語言的直譯器來解釋你所定義的語言。 但是瞭解該模式的作用還是很有意義的,萬一哪天真的需要在自己的應用中定義一些簡單的語言來表達和解決一些問題時, 至少提供瞭解決問題的一個重要思路