Ответ
Паттерн Chain of Responsibility позволяет передавать запрос по цепочке обработчиков. Каждый обработчик решает, обработать ли запрос самому или передать дальше по цепочке.
Классический пример: Система логирования с разными уровнями серьезности.
// 1. Абстрактный базовый класс обработчика
public abstract class LoggerHandler
{
protected LogLevel _level;
protected LoggerHandler? _nextHandler; // Ссылка на следующий в цепочке
public LoggerHandler(LogLevel level)
{
_level = level;
}
// Метод для установки следующего обработчика
public LoggerHandler SetNext(LoggerHandler nextHandler)
{
_nextHandler = nextHandler;
return nextHandler; // Позволяет строить цепочку fluent-стилем
}
// Основной метод обработки запроса
public void LogMessage(LogLevel level, string message)
{
if (_level <= level) // Если уровень серьезности достаточен для этого обработчика
{
Write(message); // Обрабатываем
}
// Передаем запрос дальше по цепочке, независимо от того, обработали мы его или нет
_nextHandler?.LogMessage(level, message);
}
protected abstract void Write(string message); // Конкретная реализация записи
}
// 2. Конкретные обработчики
public class ConsoleLogger : LoggerHandler
{
public ConsoleLogger(LogLevel level) : base(level) { }
protected override void Write(string message)
{
Console.WriteLine($"[CONSOLE] {DateTime.Now}: {message}");
}
}
public class FileLogger : LoggerHandler
{
private readonly string _filePath;
public FileLogger(LogLevel level, string filePath) : base(level)
{
_filePath = filePath;
}
protected override void Write(string message)
{
File.AppendAllText(_filePath, $"[FILE] {DateTime.Now}: {message}" + Environment.NewLine);
}
}
public class EmailLogger : LoggerHandler
{
public EmailLogger(LogLevel level) : base(level) { }
protected override void Write(string message)
{
// Симуляция отправки email только для критических ошибок
Console.WriteLine($"[EMAIL ALERT] Критическая ошибка: {message}");
}
}
// 3. Использование
public enum LogLevel { Info = 1, Warning = 2, Error = 3, Critical = 4 }
class Program
{
static void Main()
{
// Построение цепочки: Console -> File -> Email
var consoleLogger = new ConsoleLogger(LogLevel.Info); // Логирует всё (Info и выше)
var fileLogger = new FileLogger(LogLevel.Warning, "log.txt"); // Логирует Warning и выше
var emailLogger = new EmailLogger(LogLevel.Critical); // Логирует только Critical
// Связывание обработчиков в цепочку
consoleLogger.SetNext(fileLogger).SetNext(emailLogger);
// Отправка сообщений в начало цепочки
consoleLogger.LogMessage(LogLevel.Info, "Приложение запущено.");
// Вывод: [CONSOLE] ... (File и Email проигнорируют Info)
consoleLogger.LogMessage(LogLevel.Warning, "Загрузка CPU высокая.");
// Вывод: [CONSOLE] ... и запись в файл (Email проигнорирует Warning)
consoleLogger.LogMessage(LogLevel.Critical, "База данных недоступна!");
// Вывод: [CONSOLE] ..., запись в файл И отправка email-алерта
}
}
Где еще применяется:
- Обработка HTTP-запросов в Middleware пайплайне ASP.NET Core (каждый middleware — звено цепи).
- Валидация данных (цепочка проверок).
- Обработка событий в UI.
Преимущества:
- Уменьшает связанность: отправитель запроса не знает, кто его обработает.
- Позволяет динамически менять цепочку.
- Упрощает добавление новых обработчиков.