Clean Architecture é um padrão arquitetural que visa promover a separação de responsabilidades, facilitando a manutenção e evolução do sistema. Quando combinado com CQRS (Command Query Responsibility Segregation) e a biblioteca MediatR, é possível criar aplicações escaláveis, testáveis e de fácil manutenção em .NET.
🧭 O que é Clean Architecture?
Clean Architecture propõe uma estrutura onde as dependências fluem de fora para dentro, garantindo que o núcleo da aplicação (domínio) não dependa de detalhes de implementação, como frameworks ou bancos de dados. A estrutura típica é:
┌──────────────────┐
│ Entities │
└──────────────────┘
▲
┌──────────────────┐
│ Use Cases / Application │
└──────────────────┘
▲
┌──────────────────┐
│ Interface Adapters │
└──────────────────┘
▲
┌──────────────────┐
│ Frameworks & Drivers │
└──────────────────┘
🔄 O que é CQRS?
CQRS é um padrão que separa as operações de leitura (Query) das de escrita (Command). Isso permite otimizar cada operação de forma independente e melhora a escalabilidade e segurança da aplicação.
- Command: Representa uma ação que altera o estado do sistema.
- Query: Representa uma consulta que retorna dados sem modificá-los.
🧩 Integrando MediatR
MediatR é uma biblioteca que implementa o padrão Mediator, facilitando a comunicação entre componentes sem que eles se conheçam diretamente. Ela é ideal para implementar CQRS em .NET.
Instalação
Install-Package MediatR
Install-Package MediatR.Extensions.Microsoft.DependencyInjection
Configuração no ASP.NET Core
No arquivo Program.cs
:
builder.Services.AddMediatR(cfg =>
cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));
🛠️ Exemplo Prático
1. Definindo o Command
public class CriarPedidoCommand : IRequest<Guid>
{
public string Produto { get; set; }
public int Quantidade { get; set; }
}
2. Criando o Command Handler
public class CriarPedidoHandler : IRequestHandler<CriarPedidoCommand, Guid>
{
private readonly IPedidoRepository _pedidoRepository;
public CriarPedidoHandler(IPedidoRepository pedidoRepository)
{
_pedidoRepository = pedidoRepository;
}
public async Task<Guid> Handle(CriarPedidoCommand request, CancellationToken cancellationToken)
{
var pedido = new Pedido(request.Produto, request.Quantidade);
await _pedidoRepository.AdicionarAsync(pedido);
return pedido.Id;
}
}
3. Definindo a Query
public class ObterPedidoQuery : IRequest<Pedido>
{
public Guid Id { get; set; }
}
4. Criando o Query Handler
public class ObterPedidoHandler : IRequestHandler<ObterPedidoQuery, Pedido>
{
private readonly IPedidoRepository _pedidoRepository;
public ObterPedidoHandler(IPedidoRepository pedidoRepository)
{
_pedidoRepository = pedidoRepository;
}
public async Task<Pedido> Handle(ObterPedidoQuery request, CancellationToken cancellationToken)
{
return await _pedidoRepository.ObterPorIdAsync(request.Id);
}
}
5. Controlador ASP.NET Core
[ApiController]
[Route("api/[controller]")]
public class PedidosController : ControllerBase
{
private readonly IMediator _mediator;
public PedidosController(IMediator mediator)
{
_mediator = mediator;
}
[HttpPost]
public async Task<IActionResult> CriarPedido([FromBody] CriarPedidoCommand command)
{
var pedidoId = await _mediator.Send(command);
return CreatedAtAction(nameof(ObterPedido), new { id = pedidoId }, null);
}
[HttpGet("{id}")]
public async Task<IActionResult> ObterPedido(Guid id)
{
var pedido = await _mediator.Send(new ObterPedidoQuery { Id = id });
if (pedido == null) return NotFound();
return Ok(pedido);
}
}
✅ Vantagens da Abordagem
- Desacoplamento: Com MediatR, os componentes não se comunicam diretamente, facilitando a manutenção e evolução do sistema.
- Testabilidade: Comandos e consultas podem ser testados isoladamente.
- Escalabilidade: Permite otimizar operações de leitura e escrita de forma independente.
- Organização: A separação clara entre comandos, consultas e manipuladores facilita a compreensão do sistema.
🔗 Recursos Adicionais
- Implementando CQRS com MediatR e ASP.NET Core
- Integrando CQRS e Mediator em .NET com MediatR
- MediatR e Arquitetura Limpa em projetos .NET
Top comments (0)