我有一個三類對象的解析器:解析器本身,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
知道,所以它是由狀態來告訴解析器該做什麼。問題是Parser
到State
。我可以在狀態構造函數中注入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不。
你能解釋一下爲什麼「你想避免擴展任何東西」。對於OO代碼來說,這看起來很奇怪。 – FtDRbwLXw6 2012-04-24 18:32:12
@drrcknlsn有一個小的(我認爲)討厭繼承的人的先鋒隊,他們從來不想使用它,並在所有情況下都喜歡組合。如果有必要,我會放棄,但請記住,並非所有的州都需要訪問解析器,所以這可能不合適。 – 2012-04-24 18:35:54
我從來沒有聽說過這樣的事情。面向對象設計的一個主要優點是繼承。對於需要訪問或不訪問的兒童來說,這就是多層次繼承發揮作用的地方。那些需要訪問的會擴展一個帶有注入解析器的類(它本身可以擴展基類)。那些不需要訪問的只會擴展基類。你也可以用組合來解決這個問題,如果你想,但是...... – FtDRbwLXw6 2012-04-24 19:38:40