Chain of responsibility

Назначение

Chain of responsibility позволяет выстроить гибкую цепочку из обработчиков команды, каждый из которых принимает независимое решение об обработке и/или передаче следующему обработчику по цепочке.

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

Описание

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

Проблемы:

  • каким образом и кем будет создана последовательность обработчиков?
  • как клиент получит ссылку на первый обработчик?

Реализация

Схема

Диаграмма классов

Client
Client
Первичный источник команды, отправляющий её первому обработчику в цепочке, к которому у источника имеется ссылка через общий интерфейс всех обработчиков
Handler
Filter
Общий интерфейс всех обработчиков команды в цепочке
AbstractHandler
Абстрактный класс обработчиков, содержащий общее поведение для всех обработчиков, например, обработку команды в случае возможности её обработки и передачи дальше по цепочке в противном случае. Также часто содержит код, который обслуживает ссылку на следующий обработчик
ConcreteHandler
WelcomeFilter
Полезная реализация некоторого обработчика команды

Примеры

javax.servlet.Filter - пример обработчика, которые связаны по принципу Chain Of Responsibility. Фильтр имеет метод doFilter(request, response, filterChain) в который кроме запроса и ответа передается объект FilterChain. Этот объект отражает последовательность фильтров. Контейнер сервлетов, в зависимости от текущей конфигурации (web.xml), на каждый запрос создает соответствующий FilterChain. Таким образом, Filter явно не хранит ссылку на следующий фильтр, ему передается оставшаяся часть цепочки в качестве параметра. Последовательность филтров хранится в FilterChain.


Source: https://stackoverflow.com/questions/25196867/how-filter-chain-invocation-works

Варианты

  • есть подход, при котором обработчику в любом случае передается команда для обработки, а в процессе обработки обработчик решает, передать ли команду дальше.
  • есть подход, при котором обработчик сначала решает, сможет ли он обработать команду. Если сможет, то он обрабатывает её, дальше запрос не передается. Если не сможет, запрос передается по цепочке. Подход характерен тем, что у команды не больше одного обработчика. В таком подходе есть отдельный boolean метод для проверки и метод для обработки.
  • обработчики необязательно должны быть выстроены в виде цепочки. Обработчики могу составлять например дерево, но маршрут команды в итоге образует цепочку.

Чем отличается

Decorator имеет структуру, очень похожую на структуру Chain of responsibility. И Decorator и Chain of responsibility по сути набор последовательно связанных объектов одного типа. Шаблоны различаются назначением: Decorator для добавления некоторого поведения, Chain of responsibility для обработки. Существует мнение, что основное их отличие в том, что Chain of responsibility может прервать цепочку в любом месте и вернуть результат, в то время как для Decorator это не типично.

Ссылки

https://java-design-patterns.com/patterns/chain-of-responsibility/

https://github.com/iluwatar/java-design-patterns/tree/master/chain-of-responsibility

https://refactoring.guru/design-patterns/chain-of-responsibility

StackOverflow: How filter chain invocation works?

StackOverflow: Design Patterns Chain of Resposibility Vs Decorator

Baeldung - Chain of Responsibility Design Pattern in Java