Здесь показаны различия между двумя версиями данной страницы.
| Следующая версия | Предыдущая версия | ||
|
php:shablony_proektirovanija:behavioral_patterns:chain_of_responsibilities [2023/08/17 22:50] werwolf создано |
php:shablony_proektirovanija:behavioral_patterns:chain_of_responsibilities [2023/08/17 22:52] (текущий) werwolf |
||
|---|---|---|---|
| Строка 3: | Строка 3: | ||
| [[http://webmastermsk.ru:30000/serg/patterns-php/-/blob/main/behavioral/Chain.php|▶ code]] | [[http://webmastermsk.ru:30000/serg/patterns-php/-/blob/main/behavioral/Chain.php|▶ code]] | ||
| - | В случаях, когда требуется эффективно, компактно, надежно реализовать обработку потока информации с потенциально большим\\ | + | В случаях, когда требуется эффективно, компактно, надежно реализовать обработку потока информации с потенциально большим количеством обработчиков, используется шаблон проектирования "Цепочка обязанностей". |
| - | количеством обработчиков, используется шаблон проектирования "Цепочка обязанностей". | + | |
| - | Построить цепочку объектов для обработки вызова в последовательном порядке. Если один объект не может справиться с\\ | + | Построить цепочку объектов для обработки вызова в последовательном порядке. Если один объект не может справиться с вызовом, он делегирует вызов следующему в цепи и так далее. |
| - | вызовом, он делегирует вызов следующему в цепи и так далее. | + | |
| Шаблон "Цепочка обязанностей" позволяет: | Шаблон "Цепочка обязанностей" позволяет: | ||
| Строка 19: | Строка 17: | ||
| **Использование:** | **Использование:** | ||
| - | * Когда программа должна обрабатывать разнообразные запросы несколькими способами, но заранее неизвестно, какие\\ | + | * Когда программа должна обрабатывать разнообразные запросы несколькими способами, но заранее неизвестно, какие конкретно запросы будут приходить и какие обработчики для них понадобятся. |
| - | конкретно запросы будут приходить и какие обработчики для них понадобятся. | + | |
| * Когда важно, чтобы обработчики выполнялись один за другим в строгом порядке. | * Когда важно, чтобы обработчики выполнялись один за другим в строгом порядке. | ||
| * Когда набор объектов, способных обработать запрос, должен задаваться динамически. | * Когда набор объектов, способных обработать запрос, должен задаваться динамически. | ||
| Строка 36: | Строка 33: | ||
| **Связи с другими паттернами** | **Связи с другими паттернами** | ||
| - | * Цепочка обязанностей, Команда, Посредник и Наблюдатель показывают различные способы работы отправителей запросов с их\\ | + | * Цепочка обязанностей, Команда, Посредник и Наблюдатель показывают различные способы работы отправителей запросов с их получателями: |
| - | получателями: | + | * Цепочка обязанностей передаёт запрос последовательно через цепочку потенциальных получателей, ожидая, что какой-то из них обработает запрос. |
| - | * Цепочка обязанностей передаёт запрос последовательно через цепочку потенциальных получателей, ожидая, что какой-то\\ | + | |
| - | из них обработает запрос. | + | |
| * Команда устанавливает косвенную одностороннюю связь от отправителей к получателям. | * Команда устанавливает косвенную одностороннюю связь от отправителей к получателям. | ||
| - | * Посредник убирает прямую связь между отправителями и получателями, заставляя их общаться опосредованно, через\\ | + | * Посредник убирает прямую связь между отправителями и получателями, заставляя их общаться опосредованно, через себя. |
| - | себя. | + | * Наблюдатель передаёт запрос одновременно всем заинтересованным получателям, но позволяет им динамически подписываться или отписываться от таких оповещений. |
| - | * Наблюдатель передаёт запрос одновременно всем заинтересованным получателям, но позволяет им динамически\\ | + | * Цепочку обязанностей часто используют вместе с Компоновщиком. В этом случае запрос передаётся от дочерних компонентов к их родителям. |
| - | подписываться или отписываться от таких оповещений. | + | * Обработчики в Цепочке обязанностей могут быть выполнены в виде Команд. В этом случае множество разных операций может быть выполнено над одним и тем же контекстом, коим является запрос. |
| - | * Цепочку обязанностей часто используют вместе с Компоновщиком. В этом случае запрос передаётся от дочерних компонентов\\ | + | * Но есть и другой подход, в котором сам запрос является Командой, посланной по цепочке объектов. В этом случае одна и та же операция может быть выполнена над множеством разных контекстов, представленных в виде цепочки. |
| - | к их родителям. | + | * Цепочка обязанностей и Декоратор имеют очень похожие структуры. Оба паттерна базируются на принципе рекурсивного выполнения операции через серию связанных объектов. Но есть и несколько важных отличий. |
| - | * Обработчики в Цепочке обязанностей могут быть выполнены в виде Команд. В этом случае множество разных операций может\\ | + | * Обработчики в Цепочке обязанностей могут выполнять произвольные действия, независимые друг от друга, а также в любой момент прерывать дальнейшую передачу по цепочке. С другой стороны Декораторы расширяют какое-то определённое действие, не ломая интерфейс базовой операции и не прерывая выполнение остальных декораторов. |
| - | быть выполнено над одним и тем же контекстом, коим является запрос. | + | |
| - | * Но есть и другой подход, в котором сам запрос является Командой, посланной по цепочке объектов. В этом случае одна\\ | + | |
| - | и та же операция может быть выполнена над множеством разных контекстов, представленных в виде цепочки. | + | **Chain.php** |
| - | * Цепочка обязанностей и Декоратор имеют очень похожие структуры. Оба паттерна базируются на принципе рекурсивного\\ | + | <code php> |
| - | выполнения операции через серию связанных объектов. Но есть и несколько важных отличий. | + | |
| - | * Обработчики в Цепочке обязанностей могут выполнять произвольные действия, независимые друг от друга, а также в\\ | + | <?php |
| - | любой момент прерывать дальнейшую передачу по цепочке. С другой стороны Декораторы расширяют какое-то определённое\\ | + | |
| - | действие, не ломая интерфейс базовой операции и не прерывая выполнение остальных декораторов. | + | abstract class Handler |
| + | { | ||
| + | private ?Handler $successor; | ||
| + | |||
| + | public function __construct(?Handler $successor) | ||
| + | { | ||
| + | $this->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)); // НЕ вернет массив | ||
| + | |||
| + | </code> | ||