Что такое шаблон проектирования Chain of Responsibility (Цепочка обязанностей)?

«Что такое шаблон проектирования Chain of Responsibility (Цепочка обязанностей)?» — вопрос из категории Паттерны, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Ключевые компоненты:

  1. Handler (Обработчик): Определяет интерфейс для обработки запросов. Часто содержит ссылку на следующий обработчик.
  2. ConcreteHandler (Конкретный обработчик): Реализует логику обработки. Решает, обрабатывать ли запрос, и/или передаёт его дальше.
  3. Client (Клиент): Инициирует запрос к цепочке.

Пример реализации на Java:

// Абстрактный базовый обработчик
abstract class Logger {
    protected LogLevel level;
    protected Logger next; // Ссылка на следующий в цепи

    public Logger(LogLevel level) { this.level = level; }

    public void setNext(Logger next) { this.next = next; }

    public void logMessage(LogLevel severity, String message) {
        if (this.level.ordinal() <= severity.ordinal()) {
            write(message); // Обрабатываем, если наш уровень подходит
        }
        if (next != null) {
            next.logMessage(severity, message); // Передаём дальше
        }
    }
    abstract protected void write(String message);
}

// Конкретный обработчик
class ConsoleLogger extends Logger {
    public ConsoleLogger(LogLevel level) { super(level); }
    protected void write(String message) {
        System.out.println("[CONSOLE]: " + message);
    }
}

// Использование
Logger chain = new ConsoleLogger(LogLevel.INFO);
chain.setNext(new FileLogger(LogLevel.DEBUG));
chain.logMessage(LogLevel.ERROR, "System failure!"); // Выведет все логгеры

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

  • Ослабляет связность: отправитель запроса не знает, кто его обработает.
  • Упрощает добавление новых обработчиков.
  • Позволяет динамически менять цепочку.

Недостатки:

  • Нет гарантии, что запрос будет обработан.
  • Может привести к неэффективности при длинных цепочках.