Decorator Pattern: Entendendo o Padrão de Projeto Decorator
O Padrão de Projeto Decorator é uma solução muito bacana para adicionar funcionalidades a objetos de forma dinâmica sem que seja necessário alterar o código original, vamos entender como ele funciona e explorar um exemplo prático e ver como é simples de implementá-lo.
O que é o Padrão Decorator?
O padrão Decorator é um padrão de design estrutural que permite adicionar funcionalidades a objetos de forma dinâmica, ou seja, em tempo de execução, sem modificar o código original da classe. Ele envolve a criação de uma interface ou classe abstrata que define o comportamento básico, e classes concretas que implementam essa interface e adicionam funcionalidades extras.
Imagine que temos uma classe que é responsável por enviar notificações, mas quando precisamos adicionar novas funcionalidades e não queremos modificar o código original, com esse cenário em mente, vamos aplicar o padrão Decorator.
public interface INotificacao
{
void Enviar(string mensagem);
}
public class Notificacao : INotificacao
{
public void Enviar(string mensagem)
{
Console.WriteLine($"Notificação: {mensagem}");
}
}
Essa classe Notificacao tem um método Enviar que simplesmente imprime uma mensagem. Agora, suponha que queremos adicionar funcionalidades como enviar notificações por e-mail e uma retentativa de envio em caso de falha, mas sem alterar a classe original Notificacao. Aqui podemos usar o padrão Decorator.
public abstract class NotificacaoDecorator : INotificacao
{
protected INotificacao _notificacao;
public NotificacaoDecorator(INotificacao notificacao)
{
_notificacao = notificacao;
}
public void Enviar(string mensagem)
{
_notificacao.Enviar(mensagem);
}
}
public class NotificacaoEmail : NotificacaoDecorator
{
public NotificacaoEmail(INotificacao notificacao) : base(notificacao) { }
public override void Enviar(string mensagem)
{
base.Enviar(mensagem);
Console.WriteLine($"Enviando e-mail: {mensagem}");
}
}
public class RetentativaNotificacao : NotificacaoDecorator
{
public RetentativaNotificacao(INotificacao notificacao) : base(notificacao) { }
public override void Enviar(string mensagem)
{
try
{
base.Enviar(mensagem);
}
catch (Exception)
{
Console.WriteLine("Falha ao enviar notificação, tentando novamente...");
base.Enviar(mensagem);
}
}
}
Já temos duas classes decoradoras, a classe NotificacaoEmail para enviar e-mail, e a classe RetentativaNotificacao que vai tentar reenviar a notificação em caso de falha, agora vamos ver como usar essas classes:
class Program
{
static void Main(string[] args)
{
INotificacao notificacao = new Notificacao();
INotificacao notificacaoComEmail = new NotificacaoEmail(notificacao);
INotificacao notificacaoComRetentativa = new RetentativaNotificacao(notificacaoComEmail);
notificacaoComRetentativa.Enviar("Olá, esta é uma notificação!");
}
}
No código acima, criamos uma instância da classe Notificacao, depois a decoramos com NotificacaoEmail e RetentativaNotificacao. Quando chamamos o método Enviar, ele executa a lógica original e as funcionalidades adicionais de forma dinâmica.
Vantagens do Padrão Decorator
- Flexibilidade: Permite adicionar funcionalidades de forma dinâmica sem alterar o código original.
- Reutilização de Código: As classes decoradoras podem ser reutilizadas em diferentes contextos.
- Composição: Permite combinar várias funcionalidades de maneira simples e clara.
- Manutenção: Facilita a manutenção do código, pois cada funcionalidade adicional é encapsulada em uma classe separada.
Onde encontramos o Padrão Decorator no dia a dia?
No asp.net core, esse padrão é utilizado em middlewares, onde cada middleware pode adicionar funcionalidades adicionais ao pipeline de requisições sem modificar o código original do servidor. Essa aplicação do padrão Decorator, é pessoalmente uma das minhas favoritas, porque podemos adicionar funcionalidades como autenticação, logging, compressão, entre outras, de forma modular e reutilizável.
