Ответ
Chain of Responsibility — это поведенческий шаблон проектирования, который позволяет передавать запрос последовательно по цепочке обработчиков. Каждый обработчик решает, может ли он обработать запрос, и либо обрабатывает его, либо передаёт следующему в цепи.
Ключевые компоненты:
- Handler (Обработчик): Определяет интерфейс для обработки запросов. Часто содержит ссылку на следующий обработчик.
- ConcreteHandler (Конкретный обработчик): Реализует логику обработки. Решает, обрабатывать ли запрос, и/или передаёт его дальше.
- 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!"); // Выведет все логгеры
Преимущества:
- Ослабляет связность: отправитель запроса не знает, кто его обработает.
- Упрощает добавление новых обработчиков.
- Позволяет динамически менять цепочку.
Недостатки:
- Нет гарантии, что запрос будет обработан.
- Может привести к неэффективности при длинных цепочках.
Ответ 18+ 🔞
А, паттерн «Цепочка обязанностей»! Ну это ж классика, как Герасим с Муму, только без утопления в конце, блядь. Представь себе, ты — запрос, а перед тобой выстроилась очередь из этих... обработчиков, как на каком-нибудь ебучем митинге в отделе кадров. Каждый из них смотрит на тебя и думает: «Моё? Не моё? А, похуй, пусть следующий разбирается».
Суть в чём, ёпта: у тебя есть какая-то задача — запрос. И вместо того, чтобы пихать её в одну конкретную, заевшуюся жопу (простите, модуль), ты кидаешь её в начало цепочки. Первый чувак смотрит: «О, это по моей части!» — и обрабатывает. Или говорит: «Не, это не ко мне, иди нахуй к Васе». И так по цепочке, пока кто-то не возьмёт на себя смелость, или пока все не пошлют, и запрос не сгинет в пучине небытия. Овердохуища удобно!
Из чего состоит эта пиздопроебибна:
- Обработчик (Handler): Ну типа главный по тарелкам. Объявляет: «Ребята, я могу что-то делать, а могу и передать дальше». Часто тащит с собой ссылку на следующего бедолагу в цепи.
- Конкретный обработчик (ConcreteHandler): Это уже работяга. Он реально смотрит на запрос и решает: «А, это уровень ERROR, а я только для INFO, так что... следующий!» Или наоборот: «Так, ERROR? Это ж моя тема, щас всё порешаю!».
- Клиент (Client): Это ты, инициатор. Ты создаёшь эту цепь из страдальцев и кидаешь в неё первый камень — то бишь запрос.
Смотри, как это выглядит в коде, на примере системы логирования (всё честно, термины не трогаю):
// Абстрактный предок всех наших логгеров-страдальцев
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);
}
}
// А это — другой, пишет в файл
class FileLogger extends Logger {
public FileLogger(LogLevel level) { super(level); }
protected void write(String message) {
// ...тут код записи в файл, но мне лень
System.out.println("[ФАЙЛОВЫЙ ЛОГГЕР, СУКА]: " + message);
}
}
// Как этим пользоваться? Да легко!
public class Main {
public static void main(String[] args) {
// Строим цепь: сначала консольный (ловит INFO и выше), за ним файловый (ловит DEBUG и выше)
Logger consoleLogger = new ConsoleLogger(LogLevel.INFO);
Logger fileLogger = new FileLogger(LogLevel.DEBUG);
consoleLogger.setNext(fileLogger); // Цепляем файловый за консольным
// Кидаем запрос уровня ERROR
consoleLogger.logMessage(LogLevel.ERROR, "System failure! Всё пропало!");
// И что будет? А будет: консольник скажет "моё!" и выведет.
// Потом он передаст файловику, а тот тоже скажет "моё!" (DEBUG <= ERROR) и тоже выведет.
// Вот тебе и цепочка, хитрая жопа!
}
}
Почему это иногда охуенно:
- Слабая связность: Тот, кто кидает запрос, нихуя не знает, кто его в итоге обработает. Может, первый, а может, последний. Ему похуй.
- Гибкость: Захотел добавить нового обработчика — впендюрил его в середину цепи, и всё. Никто даже не заметил.
- Динамика: Цепь можно собирать и пересобирать на лету, как конструктор.
А где подвох, спросишь ты?
- Нет гарантии: Запрос может пройти через всю цепь, как Муму по речке, и нихуя не быть обработанным. Все отказались.
- Производительность: Если цепь длинная, как мои костыли, а запросов много, то можно проебать на передачах из рук в руки. Но это уже проблемы архитектора, который эту цепь выстроил, пидарас шерстяной.
Короче, паттерн мощный, когда нужно размазать ответственность между кучей объектов. Главное — не устроить из него бесконечный волейбол, а то так и до дедлока недалеко, в рот меня чих-пых!