Chain of Responsibility — Цепочка ответственности

Запрос идёт по цепочке обработчиков. Один из них берёт ответственность на себя и обрабатывает; остальные пропускают.

Проблема

На запрос могут реагировать несколько обработчиков. Какой именно — зависит от данных запроса (тип, права, состояние). Не хочется в одном месте знать про все обработчики и условия.

Решение

  • Обработчики связаны в односвязный список.
  • Каждый проверяет — «моё ли это?»
  • Если да — обрабатывает и останавливает цепочку.
  • Если нет — передаёт дальше.

Пример в JS

class Handler {
  setNext(h) { this.next() = h; return h; }
  handle(req) {
    if (this.canHandle(req)) return this.process(req);
    return this.next()?.handle(req);
  }
  canHandle(req) { return false; }
  process(req) {}
}

class AuthHandler extends Handler {
  canHandle(req) { return !req.user; }
  process { return { error: 'unauthorized' }; }
}

class CacheHandler extends Handler {
  canHandle(req) { return cache.has(req.url); }
  process(req) { return cache.get(req.url); }
}

class RouteHandler extends Handler {
  canHandle { return true; }
  process(req) { return route(req); }
}

const chain = new AuthHandler();
chain.setNext(new CacheHandler).setNext(new RouteHandler);
chain.handle(req);

Где используется в JS-экосистеме

  • Event bubbling в DOM — событие идёт по дереву, обработчик может вызвать stopPropagation
  • NestJS Guards — серия проверок до controller'а
  • DOM EventspreventDefault останавливает цепочку
  • Express middleware — формально похоже, но отличается! (см. ниже)

Подводные камни

  • Chain of Responsibility ≠ Middleware! В CoR один обработчик берёт ответственность. В Middleware каждый что-то делает.
  • CoR безопаснее middleware — нет shared state, не нужна синхронизация.
  • Можно реализовать без классов: массив функций и Array.prototype.find.
  • Если ни один обработчик не взял запрос — что делать? Нужен default или ошибка.

Главные тезисы автора

  • «Запрос обрабатывается несколькими, один из них берёт на себя ответственность».
  • «Chain of Responsibility безопаснее middleware» — нет race conditions через shared state.
  • «В middleware нет концентрации ответственности на одном элементе» — это ключевое отличие.
  • Middleware в Connect/Express — антипаттерн (в 2026, по автору) — потому что мутирует req/res, создавая reference pollution.
  • Цепочка обработчиков — это односвязный список обработчиков.

🎓 Источники

См. также