Система, над которой я работаю, использует что-то вроде шаблона динамического маршрутизатора + dep.injection, а именно:
- Объект маршрутизатора использует config для создания экземпляров объектов модуля.Модули независимы и могут быть множественными.
- Экземпляр объекта маршрутизатора внедряется в конструктор модуля в зависимости и используется как ссылка / указатель API (вероятно, не имеет значения для вопроса, но здесь для ясности)
- модули используют API для добавления правил, которые связывают шаблоны ввода с конкретными методами модуля
- Маршрутизатор получает входные данные, проверяет их по набору правил и вызывает методы модуля, соответствующие
- Результатысобранный маршрутизатором и переданный в выходной процессор
Конструктор модуля:
class module {
public function __construct(&$router) {
$router->addRoute('some-input-pattern', array($this, 'someMethod'));
}
public function someMethod() {
return 'some arbitrary result';
}
}
Как бы это ни показалось простым, бывают случаи, когда модулю и маршрутизатору необходимо сообщать о чем-то несвязанные с произвольными возвращаемыми значениями.
Например, бывают случаи, когда модуль должен инициировать событие или исключение, которое должно обрабатываться самим модулем.Он может возникать в любом модульном методе и должен обрабатываться определенным методом.(Наличие множества блоков try / catch в каждом методе кажется неправильным, и единственная «точка входа», которая может обработать любое исключение, находится вне модуля и в маршрутизаторе. Выдает модуль, обрабатывает модуль, но только маршрутизатор можетна самом деле ловит. Звучит неправильно.)
class module {
public function __construct(&$router) {
...
$router->addExceptionHandler('dbTableNotFoundException',
array($this, 'installSchema'));
}
}
В других случаях есть события, которые должны обрабатываться самим маршрутизатором.Например, модуль может запросить, чтобы маршрутизатор работал так, как если бы он получил специальный тип ввода, игнорируя реальный.Затем маршрутизатор должен перепроверить его в соответствии с набором правил и вызвать соответствующие методы.
public function someMethod(){
...
throw routerRestartException('special-input');
}
В других случаях события могут не требовать обработки, кроме передачи их на выход, например, ошибки только человеческого глаза.
public function someMethod(){
...
throw humanEyesException("You can't do that!");
}
Это фактически приводит меня к мысли о двух аспектах связи , поскольку маршрутизатор и модули обмениваются как произвольными возвращаемыми данными , так и специальными управляющими сообщениями.
Пока аспект системных управляющих сообщений реализован модулями, генерирующими исключения, и перехватом маршрутизатора.Это требует, чтобы модули регистрировали два типа методов - один для обработки ввода, а другой для обработки исключений, что, вероятно, вонючее.
Некоторые из исключений, кажется, влияют на управление потоком, и я считаю, что использование исключений для этого нелибо не является хорошей практикой.
Вопрос стоит, есть ли лучшая практика или шаблон для построения такого вида двухсторонней связи между объектом маршрутизатора и его зависимыми модулями?
РЕДАКТИРОВАТЬ
Мысль на этом пути: один из способов улучшить ситуацию, отсоединив обработчик исключений в модуле от маршрутизатора, может использовать шаблон Observer для пользовательских исключений:
public function __construct(&$router){
...
dbTableNotFoundException::addObserver(array($this, 'installSchema'));
}