Decorator Pattern com Scrutor no Asp.Net Core
Tags: dotnetcore, csharp, braziliandevs, designpatterns
Published: 2023-09-20 19:47:41

## 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.
 ```csharp
public interface IClienteRepositorio
{
   Task<Cliente?> ObterPorIdAsync(int id);
}
 ```
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.
   ```csharp
   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);
       }
   }
   ```
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`

```csharp
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);
        });
    }
}
```
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.

```csharp
builder.Services.AddMemoryCache();
builder.Services.AddScoped<IClienteRepositorio, ClienteRepositorio>();
builder.Services.Decorate<IClienteRepositorio, ClienteCacheRepositorio>();
```
## 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cpwl3jix2zdar3vurhk8.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qcxmkp9n0p73xa4dgjhy.png)

## 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

- [Decorator Pattern - Refactoring Guru](https://refactoring.guru/design-patterns/decorator)
- [Scrutor - Github](https://github.com/khellang/Scrutor)
- [IMemoryCache - Documentação Microsoft](https://learn.microsoft.com/pt-br/aspnet/core/performance/caching/memory?view=aspnetcore-7.0)
- [Repositório do GitHub - Rodrigo Bitencourt](https://github.com/rodrigo-schemes/aspnetcore-decorator-pattern)
- [Youtube - Milan Jovanovic] (https://www.youtube.com/watch?v=i_3I6XLAOt0)