Ответ
Да, применял паттерн Mediator, в основном через библиотеку MediatR в .NET-приложениях. Это мощный инструмент для разделения команд/запросов и их обработчиков, что особенно полезно в архитектурах, подобных Clean Architecture или CQRS.
Ключевые концепции и преимущества:
- Уменьшение связанности: Компоненты (например, контроллеры) не знают о конкретной бизнес-логике. Они отправляют сообщение (команду или запрос) через медиатор, который находит и вызывает соответствующий обработчик.
- Организация кода: Каждая бизнес-операция инкапсулируется в отдельном классе-обработчике (
IRequestHandler<TRequest, TResponse>). - Легкое добавление сквозной функциональности: Через Behaviors (конвейеры) можно централизованно добавить логирование, валидацию, кэширование или транзакции для всех или определенных запросов.
Пример реализации команды с валидацией и логированием:
-
Команда (Request):
public record CreateProductCommand(string Name, decimal Price) : IRequest<int>; -
Валидатор (FluentValidation):
public class CreateProductCommandValidator : AbstractValidator<CreateProductCommand> { public CreateProductCommandValidator() { RuleFor(x => x.Name).NotEmpty().MaximumLength(100); RuleFor(x => x.Price).GreaterThan(0); } } -
Обработчик (Handler):
public class CreateProductCommandHandler : IRequestHandler<CreateProductCommand, int> { private readonly IApplicationDbContext _context; public CreateProductCommandHandler(IApplicationDbContext context) => _context = context; public async Task<int> Handle(CreateProductCommand request, CancellationToken ct) { var product = new Product { Name = request.Name, Price = request.Price }; _context.Products.Add(product); await _context.SaveChangesAsync(ct); return product.Id; // Возвращаем ID созданного продукта } } -
Использование в контроллере:
[ApiController] [Route("api/[controller]")] public class ProductsController : ControllerBase { private readonly IMediator _mediator; public ProductsController(IMediator mediator) => _mediator = mediator; [HttpPost] public async Task<ActionResult<int>> Create(CreateProductCommand command) { var productId = await _mediator.Send(command); return Ok(productId); } }
Когда использовать: Отлично подходит для средних и крупных проектов, где важно разделение ответственности. Для простых CRUD-операций может быть избыточным.