Что это такое
Паттерн Chain of Responsibility (цепочка обязанностей) передаёт запрос по цепочке обработчиков. Каждый обработчик либо справляется с запросом сам, либо передаёт его следующему. Отправитель знает только первое звено — и никогда не знает, кто в итоге решит задачу.
Пример: линия поддержки
Проблема попадает сначала к чат-боту. То, что бот исправить не может, уходит в техподдержку; то, что не может техподдержка, уходит к менеджеру, который берёт на себя всё, что до него дошло.
Звено next имеет тип Handler | undefined, поэтому у последнего звена его просто нет. Вызов this.next?.handle(problem) происходит только тогда, когда оно есть.
Передавай дальше, пока кто-нибудь не справится
Запрос no internet проходит один шаг и останавливается в техподдержке; запрос на возврат денег проходит всю цепочку до менеджера. Вызывающий код в обоих случаях написал одну и ту же строку.
Вывод: программа на TypeScript и захваченный вывод
class Handler {
private name: string
private canFix: (problem: string) => boolean
private next: Handler | undefined
constructor(name: string, canFix: (problem: string) => boolean,
next?: Handler) {
this.name = name
this.canFix = canFix
this.next = next
}
handle(problem: string): void {
if (this.canFix(problem)) {
console.log(this.name, "решил:", problem)
return
}
console.log(this.name, "передаёт дальше")
this.next?.handle(problem)
}
}
const manager = new Handler("менеджер", () => true)
const tech = new Handler("техподдержка", (p) => p === "no internet", manager)
const bot = new Handler("чат-бот", (p) => p === "forgot password", tech)
bot.handle("no internet")
console.log("---")
bot.handle("refund request")
Когда это использовать
Используйте, когда запрос могут обработать несколько сторон и заранее неизвестно, какая именно подходит — эскалация в поддержке, middleware, обработка событий, процессы согласования.
Не используйте, когда обработчик всегда известен — вызывайте его напрямую. Цепочка из одного звена или та, что всегда заканчивается на одном и том же звене, — это обычный вызов функции в маскарадном костюме.
Плюсы и минусы
Плюсы: отправитель и получатели развязаны между собой; звенья можно свободно добавлять, удалять и менять местами; каждый обработчик остаётся небольшим.
Минусы: нет гарантии, что запрос вообще кто-то обработает — разорванная цепочка молча его проглотит; отслеживать путь запроса через много звеньев при отладке дольше.