Что это такое
Паттерн «Цепочка обязанностей» (Chain of Responsibility) передаёт запрос по цепочке обработчиков. Каждый обработчик либо сам обрабатывает запрос, либо передаёт его следующему. Отправитель знает только первое звено — и никогда не знает, кто на самом деле решит задачу.
Пример: линия поддержки
Проблема сначала попадает к чат-боту. То, что бот не может решить, уходит в техподдержку; то, что не может решить техподдержка, уходит к менеджеру, который решает всё, что к нему приходит.
Передавай дальше, пока кто-нибудь не решит
Проблема «no internet» проходит один шаг и останавливается в техподдержке; запрос «refund request» проходит всю цепочку до менеджера. Вызывающий код оба раза написал одну и ту же строку.
Вывод: полная программа на Python
from dataclasses import dataclass
from typing import Callable
@dataclass
class Handler:
name: str
can_fix: Callable[[str], bool]
next_handler: "Handler | None" = None
def handle(self, problem: str) -> None:
if self.can_fix(problem):
print(self.name, "решает:", problem)
return
print(self.name, "передаёт дальше")
if self.next_handler is not None:
self.next_handler.handle(problem)
manager = Handler("менеджер", lambda problem: True)
tech = Handler("техподдержка", lambda problem: problem == "no internet", manager)
bot = Handler("чат-бот", lambda problem: problem == "forgot password", tech)
bot.handle("no internet")
print("---")
bot.handle("refund request")
Когда его использовать
Используйте его, когда запрос могут обработать несколько участников и заранее неизвестно, кто именно, — эскалация в поддержке, middleware, обработка событий, процессы согласования.
Не используйте его, когда обработчик всегда известен, — вызывайте его напрямую. Цепочка из одного звена или цепочка, которая всегда заканчивается на одном и том же звене, — это обычный вызов функции в маскарадном костюме.
Плюсы и минусы
Плюсы: отправитель и получатели не зависят друг от друга; звенья можно свободно добавлять, удалять и переставлять; каждый обработчик остаётся небольшим.
Минусы: нет гарантии, что кто-то обработает запрос, — разорванная цепочка молча его теряет; отслеживать запрос через множество звеньев сложнее, поэтому отладка идёт медленнее.