我有一个三类对象的解析器:解析器本身,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