Skip to content

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).