2012-04-24 68 views
3

我有一個三類對象的解析器:解析器本身,Token s和State s。解析器從詞法分析器生成令牌。所有東西都是黑色方塊的,所以令牌對解析器狀態或解析器一無所知,狀態對令牌一無所知。該結構的相當簡單的版本:構成與繼承依賴注入

class Parser { 
    public function parse() { 
     $this->state = new StEmpty; 
     while ($token = $this->lexer->get()) { 
     $this->state = $this->token->expect($this); 
     } 
    } 
    public function stateStart() { 
     return $this->state->stateStart(); 
    } 
} 
class StartToken { 
    public function expect(Parser $parser) { 
     return $parser->stateStart(); 
    } 
} 
class StEmpty { 
    public function stateStart() { 
     return new StStart; 
    } 
} 

我遇到的問題是,有時當狀態改變時,解析器需要採取一些行動(如添加規則,樹當ending-規則令牌已到達)。只有State知道,所以它是由狀態來告訴解析器該做什麼。問題是ParserState。我可以在狀態構造函數中注入Parser,但不是每個State都需要解析器,這會導致很多重複的代碼(除非我有State的基類,而Parser是受保護的成員,但我想要以避免延伸任何東西)。我也可以在需要它的state方法中注入Parser,但是我也遇到類似的問題:這會造成很多重複,並且並非所有的State實現都需要給定方法的解析器。

所以我的問題是我怎麼能得到State知道Parser當它需要沒有不必要的繼承或代碼重複?如果我需要另一個完全可以接受的課程。


如果這是難以遵循,這裏是一個「拆開」版本:

class Parser { 
    public function parse() { 
     $this->state = 'StEmpty'; 

     while ($token = $this->lexer->get()) { 
     switch ($token) { 
      case 'StartToken': 
       switch ($this->state) { 
        case 'StEmpty': 
        $this->state = 'StStart'; 
        break; 
       } 
       break; 
     } 
     } 
    } 
} 

回答這個問題可以適用於其他語言,但我知道這將是更容易在允許超載的語言中使用。 PHP不。

+0

你能解釋一下爲什麼「你想避免擴展任何東西」。對於OO代碼來說,這看起來很奇怪。 – FtDRbwLXw6 2012-04-24 18:32:12

+0

@drrcknlsn有一個小的(我認爲)討厭繼承的人的先鋒隊,他們從來不想使用它,並在所有情況下都喜歡組合。如果有必要,我會放棄,但請記住,並非所有的州都需要訪問解析器,所以這可能不合適。 – 2012-04-24 18:35:54

+0

我從來沒有聽說過這樣的事情。面向對象設計的一個主要優點是繼承。對於需要訪問或不訪問的兒童來說,這就是多層次繼承發揮作用的地方。那些需要訪問的會擴展一個帶有注入解析器的類(它本身可以擴展基類)。那些不需要訪問的只會擴展基類。你也可以用組合來解決這個問題,如果你想,但是...... – FtDRbwLXw6 2012-04-24 19:38:40

回答