Инструменты пользователя

Инструменты сайта


php:shablony_proektirovanija:behavioral_patterns:chain_of_responsibilities

Цепочка Обязанностей (Chain Of Responsibilities)

▶ code

В случаях, когда требуется эффективно, компактно, надежно реализовать обработку потока информации с потенциально большим количеством обработчиков, используется шаблон проектирования «Цепочка обязанностей».

Построить цепочку объектов для обработки вызова в последовательном порядке. Если один объект не может справиться с вызовом, он делегирует вызов следующему в цепи и так далее.

Шаблон «Цепочка обязанностей» позволяет:

  • избежать жесткой зависимости отправителя запроса от его получателя;
  • организовать обработку конкретного запроса несколькими объектами, связанными в цепочку;
  • вводить конвейер для запроса с множеством возможных обработчиков;
  • упростить структурные взаимосвязи между объектами. Отправитель запроса хранит ссылку на начало цепочки, а каждый
  • получатель имеет единственную ссылку на своего преемника последующий элемент в цепочке.

Использование:

  • Когда программа должна обрабатывать разнообразные запросы несколькими способами, но заранее неизвестно, какие конкретно запросы будут приходить и какие обработчики для них понадобятся.
  • Когда важно, чтобы обработчики выполнялись один за другим в строгом порядке.
  • Когда набор объектов, способных обработать запрос, должен задаваться динамически.

Преимущества:

  • Уменьшает зависимость между клиентом и обработчиками.
  • Реализует принцип единственной обязанности.
  • Реализует принцип открытости/закрытости.

Недостатки:

  • Запрос может остаться никем не обработанным.

Связи с другими паттернами

  • Цепочка обязанностей, Команда, Посредник и Наблюдатель показывают различные способы работы отправителей запросов с их получателями:
    • Цепочка обязанностей передаёт запрос последовательно через цепочку потенциальных получателей, ожидая, что какой-то из них обработает запрос.
    • Команда устанавливает косвенную одностороннюю связь от отправителей к получателям.
    • Посредник убирает прямую связь между отправителями и получателями, заставляя их общаться опосредованно, через себя.
    • Наблюдатель передаёт запрос одновременно всем заинтересованным получателям, но позволяет им динамически подписываться или отписываться от таких оповещений.
  • Цепочку обязанностей часто используют вместе с Компоновщиком. В этом случае запрос передаётся от дочерних компонентов к их родителям.
  • Обработчики в Цепочке обязанностей могут быть выполнены в виде Команд. В этом случае множество разных операций может быть выполнено над одним и тем же контекстом, коим является запрос.
    • Но есть и другой подход, в котором сам запрос является Командой, посланной по цепочке объектов. В этом случае одна и та же операция может быть выполнена над множеством разных контекстов, представленных в виде цепочки.
  • Цепочка обязанностей и Декоратор имеют очень похожие структуры. Оба паттерна базируются на принципе рекурсивного выполнения операции через серию связанных объектов. Но есть и несколько важных отличий.
    • Обработчики в Цепочке обязанностей могут выполнять произвольные действия, независимые друг от друга, а также в любой момент прерывать дальнейшую передачу по цепочке. С другой стороны Декораторы расширяют какое-то определённое действие, не ломая интерфейс базовой операции и не прерывая выполнение остальных декораторов.

Chain.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)); // НЕ вернет массив
php/shablony_proektirovanija/behavioral_patterns/chain_of_responsibilities.txt · Последние изменения: 2023/08/17 22:52 — werwolf