2012-04-24 65 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

回答