1. 程式人生 > 實用技巧 >原始的直譯器模式(Interpreter Pattern)

原始的直譯器模式(Interpreter Pattern)

直譯器模式的定義(現實專案中很少遇到,因此直接理論先。。。)

直譯器模式是一種按照規定語法進行解析的方案,在現在專案中使用較少,其定義為:給定一門語言,定義它的方法的一種表示,並定義一個直譯器,該直譯器使用該表示來解釋語言中的句子。其構成如下:

1、AbstractExpression——抽象直譯器

具體的解釋任務由各個實現類完成,具體的直譯器分別由TerminalExpression和NonterminalExpression完成

2、TerminalExpression——終結符表示式

實現與方法中的元素相關聯的解釋操作,通過一個直譯器模式中只有一個終結符表示式,但有多個例項,對應不同的終結符。

3、NonterminalExpression——非終結符表示式

文法中的每條規則對應於一個非終結表示式。非終結符表示式根據邏輯的複雜程式而增加,原則上每個文法規則對應一個非終結符表示式。

4、Context——環境角色

那現在用直譯器模式來解釋一下四則運算(加減乘除),類圖如下:


圖中MathExpression為抽象直譯器,Literal、Variable為終結符表示式,Sum、Multiply為非終結符表示式,結構很清晰。實現程式碼如下:

PHP程式碼:

<?php  
  
interface MathExpression  
{  
    
public function evaluate( array $values ); } /** * A terminal expression which is a literal value. */ class Literal implements MathExpression { private $_value; public function __construct( $value ) { $this->_value = $value; } public function evaluate( array
$values ) { return $this->_value; } } /** * A terminal expression which represents a variable. */ class Variable implements MathExpression { private $_letter; public function __construct( $letter ) { $this->_letter = $letter; } public function evaluate( array $values ) { return $values[$this->_letter]; } } /** * Nonterminal expression. */ class Sum implements MathExpression { private $_a; private $_b; public function __construct( MathExpression $a, MathExpression $b ) { $this->_a = $a; $this->_b = $b; } public function evaluate( array $values ) { return $this->_a->evaluate( $values ) + $this->_b->evaluate( $values ); } } /** * Nonterminal expression. */ class Multiply implements MathExpression { private $_a; private $_b; public function __construct( MathExpression $a, MathExpression $b ) { $this->_a = $a; $this->_b = $b; } public function evaluate( array $values ) { return $this->_a->evaluate( $values ) * $this->_b->evaluate( $values ); } } // 10(a + 3) $expression = new Multiply( new Literal( 10 ), new Sum( new Variable( 'a' ), new Literal( 3 ) ) ); echo $expression->evaluate( array( 'a' => 111 ) ), "\n"; 執行結果:1140 [Finished in 0.1s]

我們來看看這麼寫的優缺點

直譯器模式的優點

直譯器模式是一個簡單語法分析工具,它最顯著的優點就是擴充套件性,修改語法規則只要修改相應的非終結符表示式就可以了,若擴充套件語法,則只要增加非終結符類就可以了。

直譯器模式的缺點

1、直譯器模式會引起類膨脹(感覺好多模式都有這個問題啊)

每個語法都要產生一個非終結符表示式,語法規則比較複雜時,就可以產生大量的類檔案,為維護帶來了非常多的麻煩。

2、直譯器模式採用遞迴呼叫方法

每個終結符表示式只關心與自己有關的表示式,每個表示式需要知道最終的結果,必須一層一層地剝繭,無論是面向過程的語言還是面向物件的語言,遞迴都是在必要條件下使用的,它導致除錯非常複雜。

3、效率問題

有遞迴自然就會有效率問題,特別是用於解釋複雜冗長的語法時。

直譯器模式的使用場景

1、重複發生的問題可以使用直譯器模式

例如伺服器日誌的分析處理,由於各個伺服器的日誌模式不同,但是資料要素是相同的,按照直譯器模式的說法就是終結符表示式都是相同的,但是非終結符表示式就需要制定了。

2、一個簡單語法需要解釋的場景

例如 SQL語法分析

直譯器模式的注意事項

儘量不要在重要的模組中使用直譯器模式,否則維護會是一個很大的問題。在專案中可以使用shell,JRuby,Groovy等指令碼語言代替直譯器模式,彌補php效率上的不足。

一般在大中型的框架型專案能夠找到它的身影,如一些資料分析工具,報表設計工具,科學計算工具等,若你確實遇到“一種特定型別的問題發生的頻率足夠高”的情況,準備使用直譯器模式時,可以考慮一下Expression4J,MESP,Jep等開源的解析工具包,功能都異常強大,沒必要自己從頭編寫直譯器。

轉載於:https://www.iteye.com/blog/lobert-2065604