Immagine di copertina: Mediator Pattern con MediatR: CQRS e Architettura Pulita in C#

Mediator Pattern con MediatR: CQRS e Architettura Pulita in C#

2024/08/07

La tendenza degli ultimi anni è verso alla semplificazione delle applicazioni e il miglioramento delle interazioni utente, anche in sistemi complessi. Tuttavia, dietro le quinte, ottenere questa esperienza utente fluida spesso richiede algoritmi intricati e molteplici interazioni API. In questo articolo, esploreremo alcune strategie di sviluppo per snellire il codice back-end, rendendolo più chiaro, manutenibile e piacevole da utilizzare.

Cos'è il Pattern Mediator?

Il Pattern Mediator è un design pattern utilizzato principalmente per ridurre la complessità di comunicazione dirette tra oggetti e classi, aumentando la flessibilità e facilitando la manutenzione del codice. Il suo scopo principale è promuovere un accoppiamento debole centralizzando le comunicazioni esterne tra classi all'interno di un singolo oggetto mediatore.

Vantaggi

  • Promuove l'accoppiamento debole
  • Migliora la manutenibilità e riusabilità del codice
  • Evita referenze circolari

Quando Utilizzare il Pattern Mediator?

Il Pattern Mediator è particolarmente utile in situazioni in cui:

  • Un sistema comprende più classi e oggetti che devono interagire
  • Si vuole evitare un accoppiamento stretto e dipendenze complesse
  • Si prevedono frequenti cambiamenti nelle interazioni tra classi

Esempio semplificato di implementazione

Questo blocco di codice definisce due tipi di richieste utilizzando MediatR: un comando per aggiornare il nome di un utente e una query per recuperare il nome di un utente. Utilizzare richieste distinte per operazioni di lettura e scrittura è una pratica comune in architetture come CQRS (Command Query Responsibility Segregation).

using MediatR;

public class UpdateUserNameCommand : IRequest<bool>
{
    public Guid UserId { get; }
    public string NewUserName { get; }

    public UpdateUserNameCommand(Guid userId, string newUserName)
    {
        UserId = userId;
        NewUserName = newUserName;
    }
}

public class GetUserNameQuery : IRequest<string>
{
    public Guid UserId { get; }

    public GetUserNameQuery(Guid userId)
    {
        UserId = userId;
    }
}

I seguenti blocchi di codice mostrano come implementare gli handler per le richieste definite sopra:

using MediatR;
using Microsoft.Extensions.Logging;

public class UpdateUserNameCommandHandler : IRequestHandler<UpdateUserNameCommand, bool>
{
    private readonly ILogger<UpdateUserNameCommandHandler> _logger;

    public UpdateUserNameCommandHandler(ILogger<UpdateUserNameCommandHandler> logger)
    {
        _logger = logger;
    }

    public async Task<bool> Handle(UpdateUserNameCommand request, CancellationToken cancellationToken)
    {
        _logger.LogInformation($"Updating user {request.UserId} to {request.NewUserName}");
        return true; // Simulazione di successo
    }
}

Handler per la Query

public class GetUserNameQueryHandler : IRequestHandler<GetUserNameQuery, string>
{
    private readonly ILogger<GetUserNameQueryHandler> _logger;

    public GetUserNameQueryHandler(ILogger<GetUserNameQueryHandler> logger)
    {
        _logger = logger;
    }

    public async Task<string> Handle(GetUserNameQuery request, CancellationToken cancellationToken)
    {
        _logger.LogInformation($"Fetching user name for user {request.UserId}");
        return "User Name"; // Simulazione di un nome utente
    }
}

L'adozione del pattern Mediator grazie alla libreria MediatR da il meglio di sé in progetti complessi. Questa metodologia consente agli sviluppatori di concentrarsi sulle necessità di business, semplificando la struttura del codice e migliorando la sua manutenibilità.

Definendo chiaramente comandi e query con i rispettivi handler, MediatR facilita la gestione delle operazioni e l'isolamento delle funzionalità, rendendo il sistema più robusto, facile da estendere e semplifica l'unit testing.

Parliamone!

Raccontaci il tuo progetto e ti risponderemo al più presto.