Mediator Pattern: Decoupling Object Interactions
Mediator Pattern: Decoupling Object Interactions
The Mediator Pattern is a behavioral design pattern that lets you reduce chaotic dependencies between objects. The pattern restricts direct communications between the objects and forces them to collaborate only via a mediator object.
ποΈ The Problem
In a complex Web API, a Controller might need to call multiple services, repositories, and logging systems. As the app grows, the dependencies in the Controller constructor become unmanageable (Constructor Over-Injection).
π The .NET Implementation (using MediatR)
In .NET, MediatR is the industry standard for implementing the Mediator pattern.
1. The Request (Message)
using MediatR;
public class CreateUserCommand : IRequest<int>
{
public string Name { get; set; }
}2. The Handler (The logic)
public class CreateUserHandler : IRequestHandler<CreateUserCommand, int>
{
public async Task<int> Handle(CreateUserCommand request, CancellationToken ct)
{
Console.WriteLine($"[MEDIATOR]: Saving user {request.Name} to DB...");
return 123; // Simulated User ID
}
}3. The Client (The Controller)
The Controller only needs to depend on IMediator!
public class UserController : ControllerBase
{
private readonly IMediator _mediator;
public UserController(IMediator mediator) => _mediator = mediator;
[HttpPost]
public async Task<IActionResult> Create(CreateUserCommand command)
{
// π ONE dependency, regardless of how complex the handler is!
var userId = await _mediator.Send(command);
return Ok(userId);
}
}π‘ Why use Mediator?
- Decoupling: Objects donβt know about each other; they only know the Mediator.
- SRP (Single Responsibility): Each Handler does exactly one thing.
- Maintainability: Adding a new feature doesnβt require changing existing services or controllers.
- CQRS: Mediator is the perfect foundation for implementing CQRS (Commands and Queries).