===== Цепочка Обязанностей (Chain Of Responsibilities) ===== [[http://webmastermsk.ru:30000/serg/patterns-php/-/blob/main/behavioral/Chain.php|▶ code]] В случаях, когда требуется эффективно, компактно, надежно реализовать обработку потока информации с потенциально большим количеством обработчиков, используется шаблон проектирования "Цепочка обязанностей". Построить цепочку объектов для обработки вызова в последовательном порядке. Если один объект не может справиться с вызовом, он делегирует вызов следующему в цепи и так далее. Шаблон "Цепочка обязанностей" позволяет: * избежать жесткой зависимости отправителя запроса от его получателя; * организовать обработку конкретного запроса несколькими объектами, связанными в цепочку; * вводить конвейер для запроса с множеством возможных обработчиков; * упростить структурные взаимосвязи между объектами. Отправитель запроса хранит ссылку на начало цепочки, а каждый * получатель имеет единственную ссылку на своего преемника последующий элемент в цепочке. **Использование:** * Когда программа должна обрабатывать разнообразные запросы несколькими способами, но заранее неизвестно, какие конкретно запросы будут приходить и какие обработчики для них понадобятся. * Когда важно, чтобы обработчики выполнялись один за другим в строгом порядке. * Когда набор объектов, способных обработать запрос, должен задаваться динамически. **Преимущества:** * Уменьшает зависимость между клиентом и обработчиками. * Реализует принцип единственной обязанности. * Реализует принцип открытости/закрытости. **Недостатки:** * Запрос может остаться никем не обработанным. **Связи с другими паттернами** * Цепочка обязанностей, Команда, Посредник и Наблюдатель показывают различные способы работы отправителей запросов с их получателями: * Цепочка обязанностей передаёт запрос последовательно через цепочку потенциальных получателей, ожидая, что какой-то из них обработает запрос. * Команда устанавливает косвенную одностороннюю связь от отправителей к получателям. * Посредник убирает прямую связь между отправителями и получателями, заставляя их общаться опосредованно, через себя. * Наблюдатель передаёт запрос одновременно всем заинтересованным получателям, но позволяет им динамически подписываться или отписываться от таких оповещений. * Цепочку обязанностей часто используют вместе с Компоновщиком. В этом случае запрос передаётся от дочерних компонентов к их родителям. * Обработчики в Цепочке обязанностей могут быть выполнены в виде Команд. В этом случае множество разных операций может быть выполнено над одним и тем же контекстом, коим является запрос. * Но есть и другой подход, в котором сам запрос является Командой, посланной по цепочке объектов. В этом случае одна и та же операция может быть выполнена над множеством разных контекстов, представленных в виде цепочки. * Цепочка обязанностей и Декоратор имеют очень похожие структуры. Оба паттерна базируются на принципе рекурсивного выполнения операции через серию связанных объектов. Но есть и несколько важных отличий. * Обработчики в Цепочке обязанностей могут выполнять произвольные действия, независимые друг от друга, а также в любой момент прерывать дальнейшую передачу по цепочке. С другой стороны Декораторы расширяют какое-то определённое действие, не ломая интерфейс базовой операции и не прерывая выполнение остальных декораторов. **Chain.php** successor = $successor; } /** * Этот подход с использованием шаблонного метода pattern гарантирует вам, что * каждый подкласс не забудет вызвать преемника */ final public function handle(TaskInterface $task): ?array { // запрос не был обработан этим обработчиком => смотрите следующий $proceed = $this->processing($task); if ($proceed === null && $this->successor) { $proceed = $this->successor->handle($task); } return $proceed; } abstract public function processing(TaskInterface $task): ?array; } interface TaskInterface { public function getArray(): array; } class DevTask implements TaskInterface { private array $arr = [1, 2, 3,]; public function getArray(): array { return $this->arr; } } class Senior extends Handler { public function processing(TaskInterface $task): ?array { return $task->getArray(); } } class Middle extends Handler { public function processing(TaskInterface $task): ?array { return null; } } class Jun extends Handler { public function processing(TaskInterface $task): ?array { return null; } } // 1 $task = new DevTask(); $senior = new Senior(null); $middle = new Middle($senior); $jun = new Jun($middle); print_r($jun->handle($task)); // вернет массив // 2 $task2 = new DevTask(); $jun = new Jun(null); print_r($jun->handle($task2)); // НЕ вернет массив