У меня есть анализатор с тремя классами объектов: сам анализатор, Token
и State
. Парсер генерирует токены из лексера. Все черное окно, поэтому токены ничего не знают о состоянии парсера или парсере, и государство ничего не знает о токенах. Довольно простой вариант расположения:Комбинация против инъекции зависимостей наследования
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
s, а Parser
был защищенным членом, но я хочу чтобы не расширять что-либо). Я мог бы также ввести Parser
в методы state
, которые ему нужны, но у меня есть аналогичная проблема: это было бы много дублирования, и не всем реализациям 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
@ drrcknlsn есть небольшой (я думаю) авангард людей, которые ненавидят наследование настолько, что они никогда не хотят использовать его и предпочитают композицию во всех случаях. Я буду смягчать, если это необходимо, но имейте в виду, что не все государства нуждаются в доступе к синтаксическому анализатору в любом случае, поэтому это может быть даже не уместным. –
Я никогда не слышал об этом. Одним из основных преимуществ дизайна OO является наследование. Что касается детей, нуждающихся в доступе или нет, то здесь начинают действовать несколько уровней наследования. Те, кому нужен доступ, будут расширять класс, в который вводится Parser (который сам расширяет базовый класс). Те, кому не нужен доступ, просто расширят базовый класс. Вы также можете решить это с помощью композиции, если хотите, но meh ... – FtDRbwLXw6