Приведи пример цепочки обязанностей
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Пример паттерна "Цепочка обязанностей" (Chain of Responsibility)
Паттерн Цепочка обязанностей позволяет передавать запрос последовательно через цепочку обработчиков. Каждый обработчик решает, может он обработать запрос или передать следующему в цепи. Это полезно для реализации различных политик валидации, логгирования, аутентификации или обработки событий с разными уровнями сложности.
Ключевые компоненты паттерна
- Handler (обработчик) – абстрактный класс или интерфейс, определяющий метод обработки запроса и ссылку на следующий обработчик.
- ConcreteHandler (конкретный обработчик) – реализует логику обработки. Если он может обработать запрос – делает это, иначе передаёт следующему.
- Client (клиент) – создаёт цепочку и отправляет запрос первому обработчику.
Практический пример: обработка заказа
Рассмотрим систему обработки заказа, где нужно выполнить проверку доступности товара, проверку баланса пользователя и финальное подтверждение.
1. Определяем абстрактный обработчик
public abstract class OrderHandler
{
protected OrderHandler? _nextHandler;
public void SetNext(OrderHandler handler)
{
_nextHandler = handler;
}
public abstract void Handle(OrderRequest request);
}
2. Создаём конкретные обработчики
Проверка доступности товара:
public class AvailabilityHandler : OrderHandler
{
public override void Handle(OrderRequest request)
{
if (request.ProductAvailable)
{
Console.WriteLine("✅ Товар доступен. Передаём следующему обработчику.");
if (_nextHandler != null)
_nextHandler.Handle(request);
}
else
{
Console.WriteLine("❌ Товар недоступен. Обработка прерывается.");
// Можно добавить логику возврата ошибки
}
}
}
Проверка баланса пользователя:
public class BalanceHandler : OrderHandler
{
public override void Handle(OrderRequest request)
{
if (request.UserBalance >= request.OrderPrice)
{
Console.WriteLine("✅ Баланс достаточен. Передаём следующему обработчику.");
if (_nextHandler != null)
_nextHandler.Handle(request);
}
else
{
Console.WriteLine("❌ Недостаточно средств. Обработка прерывается.");
}
}
}
Финальное подтверждение заказа:
public class ConfirmationHandler : OrderHandler
{
public override void Handle(OrderRequest request)
{
Console.WriteLine($"✅ Заказ на сумму {request.OrderPrice} подтверждён!");
// Здесь можно добавить логику сохранения заказа в БД
}
}
3. Класс запроса и клиентский код
public class OrderRequest
{
public bool ProductAvailable { get; set; }
public decimal UserBalance { get; set; }
public decimal OrderPrice { get; set; }
}
public class Client
{
public void ProcessOrder()
{
// Создаём цепочку обработчиков
var availabilityCheck = new AvailabilityHandler();
var balanceCheck = new BalanceHandler();
var confirmation = new ConfirmationHandler();
availabilityCheck.SetNext(balanceCheck);
balanceCheck.SetNext(confirmation);
// Создаём запрос
var request = new OrderRequest
{
ProductAvailable = true,
UserBalance = 5000,
OrderPrice = 3000
};
// Начинаем обработку с первого звена цепи
availabilityCheck.Handle(request);
}
}
Преимущества паттерна
- Уменьшает coupling (зависимость) – каждый обработчик независим и знает только о следующем звене.
- Динамическая конфигурация цепи – можно легко добавлять, удалять или изменять порядок обработчиков.
- Гибкость – логика обработки распределена между классами, что упрощает поддержку и тестирование.
Типичные сценарии применения в C# Backend
- Middleware в ASP.NET Core – каждый middleware компонент является звеньем цепи, обрабатывающим HTTP-запрос.
- Валидация данных – последовательная проверка разных условий (формат, длина, безопасность).
- Системы логгирования – разные обработчики для записи в файл, отправки в Elasticsearch или уведомления администратора.
- Обработка исключений – цепочка попыток восстановления (повтор запроса, использование резервного сервиса, запись в журнал).
Использование цепочки обязанностей делает код более модульным и адаптивным к изменениям бизнес-правил, что критически важно для сложных backend-систем.