DEV Community

Rodrigo Schemes
Rodrigo Schemes

Posted on

Decorator Pattern com Scrutor no Asp.Net Core

Introdução

Uma das vantagens do ASP.NET Core é a sua capacidade de usar injeção de dependência para gerenciar serviços e componentes. No entanto, às vezes você pode precisar adicionar funcionalidades adicionais a esses serviços sem modificar seu código. É aí que o Decorator Pattern entra em jogo, e uma ótima maneira de implementá-lo é usando a biblioteca Scrutor.

Decorator Pattern

O Decorator Pattern é um padrão de design estrutural que permite adicionar comportamento adicional a um objeto existente, sem modificar sua estrutura. Isso é feito criando classes decoradoras que envolvem o objeto original e adicionam as funcionalidades desejadas.

Scrutor

O Scrutor é uma biblioteca para facilitar a implementação do Decorator Pattern ao injetar serviços em tempo de execução. Ele fornece uma maneira simples e limpa de adicionar funcionalidades a serviços existentes.

Implementando o Decorator Pattern com Scrutor

Vamos dar uma olhada em como implementar o Decorator Pattern com o Scrutor em um exemplo prático.

Suponha que você tenha um repositório IClienteRepositorio que realiza operações relacionadas a Clientes em sua API. Você deseja adicionar uma camada de cache a esse serviço sem modificar seu código existente.

1. Crie uma Interface do seu Repositório de Clientes: Essa interface é usada para representar um repositório de clientes, onde você pode buscar um cliente por seu ID.

public interface IClienteRepositorio
{
   Task<Cliente?> ObterPorIdAsync(int id);
}
Enter fullscreen mode Exit fullscreen mode

2. Implemente a Interface do Repositório: Esta classe ClienteRepositorio implementa a interface IClienteRepositorio e fornece uma implementação para o método ObterPorIdAsync, que busca um cliente pelo seu ID em um contexto de banco de dados.

   public class ClienteRepositorio : IClienteRepositorio
   {
       private readonly AppDbContexto _appDbContexto;

       public ClienteRepositorio(AppDbContexto appDbContexto)
       {
           _appDbContexto = appDbContexto;
       }

       public async Task<Cliente?> ObterPorIdAsync(int id)
       {
           return await _appDbContexto
               .Set<Cliente>()
               .FirstOrDefaultAsync(cliente => cliente.ClienteId == id);
       }
   }
Enter fullscreen mode Exit fullscreen mode

3. Crie a Classe do Decorator: Essa classe será a implementação do Cache. Ela deverá implementar a interface original do repositório de Clientes. Para simplificar o exemplo, vou utilizar o próprio serviço de Cache em memória do Asp.Net Core, o IMemoryCache

public class ClienteCacheRepositorio : IClienteRepositorio
{
    private readonly IClienteRepositorio _clienteRepositorio;
    private readonly IMemoryCache _memoryCache;

    public ClienteCacheRepositorio(IClienteRepositorio clienteRepositorio, 
        IMemoryCache memoryCache)
    {
        _clienteRepositorio = clienteRepositorio;
        _memoryCache = memoryCache;
    }

    public async Task<Cliente?> ObterPorIdAsync(int id)
    {
        var chave = $"cliente-{id}";

        return await _memoryCache.GetOrCreateAsync(chave, async cacheEntry =>
        {
            cacheEntry.SetAbsoluteExpiration(TimeSpan.FromMinutes(5));
            return await _clienteRepositorio.ObterPorIdAsync(id);
        });
    }
}
Enter fullscreen mode Exit fullscreen mode

4. Instale o pacote Scrutor: você pode usar o gerenciador de pacotes NuGet com o seguinte comando: dotnet add package Scrutor.

5. Configure a Injeção de Dependência com o Scrutor: No Program.cs, configure a injeção de dependência para usar a classe do Decorator quando o IClienteRepositorio for solicitado.

builder.Services.AddMemoryCache();
builder.Services.AddScoped<IClienteRepositorio, ClienteRepositorio>();
builder.Services.Decorate<IClienteRepositorio, ClienteCacheRepositorio>();
Enter fullscreen mode Exit fullscreen mode

Testando a implementação

Podemos validar o funcionamento do padrão Decorator com o Scrutor através do Debug. Se colocarmos um breakpoint na implementação do método ObterPorIdAsync, ele será executado apenas na primeira vez. Na segunda chamada, será utilizado o Memory Cache.

Podemos verificar o resultado através do tempo de resposta no Postman. Na primeira chamada da API, obtemos o cliente com o código "1". O tempo de resposta foi de 413 ms.

Postman - Primeira Chamada

Na segunda chamada, podemos perceber a diferença no tempo de resposta, que foi de 10 ms, pois ele estava utilizando o cache de memória.

Postman - Segunda Chamada

Conclusão

O Decorator Pattern é uma ferramenta poderosa para adicionar funcionalidades a objetos sem modificar seu código existente. Com o Scrutor em ASP.NET Core, você pode implementar facilmente o padrão Decorator ao injetar serviços em tempo de execução. Isso permite que você mantenha seu código limpo, modular e facilmente extensível.

Em resumo, os benefícios do Decorator Pattern são:

  1. Flexibilidade: Permite adicionar funcionalidades extras a objetos sem modificar seu código original.
  2. Manutenção Simples: Facilita a manutenção e evita classes excessivamente complexas.
  3. Composição Dinâmica: Permite combinar funcionalidades de maneira flexível.
  4. Reutilização de Código: Os decoradores podem ser reutilizados em diferentes partes do sistema.
  5. Segregação de Responsabilidades: Mantém as classes com responsabilidades únicas.
  6. Adere aos Princípios SOLID: Segue princípios de design de software sólidos.
  7. Escalabilidade: Facilita a adição de novas funcionalidades sem alterar o código existente.

Referências

Top comments (0)