No desenvolvimento de software com Delphi, a herança é frequentemente a primeira ferramenta utilizada para estender comportamentos. No entanto, ela é uma relação estática de “é um” definida em tempo de compilação. Quando tentamos combinar múltiplas funcionalidades opcionais, caímos na armadilha da Explosão de Subclasses. O padrão Decorator surge como a solução definitiva, permitindo adicionar responsabilidades a objetos de forma dinâmica e granular.
Um dos erros mais comuns no desenvolvimento Delphi é tentar resolver toda e qualquer variação de comportamento através da herança. Se você tem uma classe TServico, e precisa de uma versão com log, cria TServicoComLog. Se precisa de uma com validação, cria TServicoComValidacao. E se precisar de ambas? Você acaba com um emaranhado de classes impossível de manter.
O padrão Decorator resolve isso permitindo que você “envolva” um objeto com camadas de funcionalidades adicionais em tempo de execução, sem alterar sua estrutura original.
1. O Problema da Herança Rígida e a Explosão de Subclasses
O erro clássico do desenvolvedor é tentar resolver toda variação de comportamento através da subclassificação. Imagine uma classe TNotificacao. Se você precisa de logs, cria TNotificacaoComLog. Se precisa de envio para a nuvem, cria TNotificacaoNuvem. E se precisar de ambos? Você acaba criando TNotificacaoComLogENuvem.
Por que este modelo faliu no Delphi 13?
- Rigidez Arquitetural: Uma vez instanciado, um objeto não pode mudar sua natureza. A decisão é imutável durante o ciclo de vida da instância.
- Manutenção Exponencial: Alterar uma regra base exige revisar toda a árvore de herança. Como o Delphi não suporta herança múltipla de classes, a reutilização de código entre ramos diferentes da árvore torna-se impossível sem duplicação.
- Violação do SRP e OCP: A classe base acaba acumulando
ifspara prever variações, tornando-se um “Objeto Deus” difícil de testar e manter.
A transição para o Clean Code proposta pelo Decorator substitui o “é um” (herança) pelo “tem um” (composição), permitindo que funcionalidades sejam “empilhadas” como blocos.
2. Implementação Técnica: “Envelopando” Objetos no Delphi 13
A essência do Decorator reside na simbiose entre Interfaces e Composição. Tanto o objeto core quanto seus decoradores implementam a mesma interface. No Delphi 13, utilizamos TInterfacedObject para garantir que a cadeia de objetos seja gerenciada via contagem de referência (ARC).
Exemplo Prático: Pipeline de Processamento de Pedidos
unit Regys.Patterns.Decorator;
interface
uses
System.SysUtils;
type
// 1. O Contrato: Define o comportamento comum
IPedido = interface
['{E1D2C3B4-A5F6-4789-B0C1-D2E3F4A5B6C7}']
function CalcularTotal: Currency;
end;
// 2. O Objeto Core: Lógica de negócio pura
TPedidoSimples = class(TInterfacedObject, IPedido)
public
function CalcularTotal: Currency;
end;
// 3. O Decorator Base: Abstrai a composição
TPedidoDecorator = class(TInterfacedObject, IPedido)
protected
FPedido: IPedido;
public
constructor Create(APedido: IPedido);
function CalcularTotal: Currency; virtual;
end;
// 4. Decoradores Concretos
TLogisticaDecorator = class(TPedidoDecorator)
public
function CalcularTotal: Currency; override;
end;
TImpostoDecorator = class(TPedidoDecorator)
public
function CalcularTotal: Currency; override;
end;
implementation
{ TPedidoSimples }
function TPedidoSimples.CalcularTotal: Currency;
begin
Result := 100.00;
end;
{ TPedidoDecorator }
constructor TPedidoDecorator.Create(APedido: IPedido);
begin
inherited Create;
FPedido := APedido;
end;
function TPedidoDecorator.CalcularTotal: Currency;
begin
Result := FPedido.CalcularTotal;
end;
{ TLogisticaDecorator }
function TLogisticaDecorator.CalcularTotal: Currency;
begin
Result := inherited CalcularTotal + 25.00; // Adiciona Frete
end;
{ TImpostoDecorator }
function TImpostoDecorator.CalcularTotal: Currency;
begin
Result := inherited CalcularTotal * 1.10; // Adiciona 10% de Imposto
end;
end.
3. Aplicação no Dia a Dia: Middlewares e Extensão Dinâmica
O uso do Decorator no Delphi 13 brilha quando precisamos adicionar comportamentos que são transversais à lógica de negócio (o que chamamos de Cross-Cutting Concerns). Em vez de poluir sua classe principal com logs, validações e controles de cache, você os separa em camadas.
A. Middlewares de Processamento
Em arquiteturas modernas de backend (como APIs em Horse ou DataSnap), o Decorator atua como um Middleware.
- Cenário de Uso: Imagine um serviço de
IProcessamentoPedido. Você pode envolver a implementação base com umTValidacaoDecorator(que verifica regras de estoque), umTAuthDecorator(que checa permissões do usuário) e umTCacheDecorator(que evita reprocessar pedidos idênticos). - Transição Clean: No modelo antigo, sua classe teria dezenas de
ifse dependências injetadas apenas para controle. Com o Decorator, sua classe base foca apenas no processamento, enquanto as camadas externas garantem a segurança e a performance.
B. Otimização de UI e Notificações (VCL/FMX)
No desenvolvimento de interfaces, o Decorator permite estender componentes sem criar descendentes complexos.
- Exemplo Real: Se você tem um provedor de dados
IDataProviderque alimenta umTStringGrid, você pode criar umTThreadSafeDecorator. Este decorador envolve as chamadas de busca de dados em umTThread.Synchronize, garantindo que qualquer implementação de provedor funcione com a UI sem que o provedor original saiba da existência de threads ou componentes visuais.
C. A Composição como Alternativa à Herança
O maior ganho no dia a dia é a capacidade de “montar” seu objeto de acordo com o contexto (configurações do .ini ou banco de dados):
// Exemplo de composição dinâmica no Delphi 13
var Servico: IServico;
begin
Servico := TServicoBase.Create;
if Config.LogHabilitado then
Servico := TLogDecorator.Create(Servico);
if Config.AmbienteProducao then
Servico := TValidacaoFiscalDecorator.Create(Servico);
Servico.Executar;
end;
Neste cenário, a variável Servico é polimórfica. O código consumidor não sabe se está executando o serviço puro ou uma versão com cinco camadas de proteção. Isso torna o sistema extremamente fácil de estender: para adicionar uma nova regra, você cria uma nova classe Decorator e a insere no pipeline de construção.
4. Nuances Técnicas: Memória, Performance e ARC no Delphi 13
Implementar o padrão Decorator no Delphi 13 exige mais do que apenas criar classes; exige maestria no ciclo de vida dos objetos. Como este padrão se baseia fortemente em “objetos que possuem outros objetos”, o risco de vazamentos ou degradação de performance deve ser mitigado.
A. Gerenciamento Automático de Memória (ARC com Interfaces)
No Delphi 13, a implementação preferencial do Decorator utiliza Interfaces. Isso é uma decisão estratégica: como cada decorador mantém uma referência para o objeto interno, o uso de IInterface garante que, quando o decorador mais externo sair de escopo, a cadeia de destruição seja acionada automaticamente por contagem de referência.
Dica de Especialista: Se você utilizar o Decorator com classes puras (
TObject), terá um pesadelo de gestão de memória, pois cada decorador precisaria ser responsável peloFreedo objeto interno. No Delphi moderno, Interfaces são obrigatórias para este padrão.
B. O Custo da Indireção e Inlining
Cada camada de um Decorator adiciona uma chamada de método virtual ao pipeline. No entanto, o compilador do Delphi 13 é altamente otimizado para lidar com tabelas de métodos virtuais (VMTs).
- Performance: Em 99% dos casos de negócio (acesso a banco, cálculos fiscais, chamadas de API), o overhead de nanosegundos causado pela indireção do Decorator é irrelevante.
- Otimização: Para métodos críticos, o uso da diretiva
inlinenos métodos do decorador base pode ajudar, mas lembre-se que chamadas via Interface são resolvidas em tempo de execução, limitando algumas otimizações de compilação.
C. A Armadilha da Referência Circular
Embora o Decorator seja projetado para ser um fluxo unidirecional (de fora para dentro), em implementações complexas o objeto base pode tentar notificar algo “para cima”.
- O Risco: Isso pode criar referências circulares, impedindo que a contagem de referência chegue a zero.
- A Solução: No Delphi 13, utilize o atributo
[Weak]se houver qualquer necessidade de o objeto decorado referenciar seu decorador ou um coordenador externo, garantindo que o objeto possa ser liberado corretamente.
D. Decoradores Genéricos (Generics)
Um recurso avançado do Delphi 13 é a criação de decoradores genéricos. Podemos criar um TLoggingDecorator<T: IInterface> que utiliza a RTTI estendida do Delphi para interceptar chamadas e logar parâmetros. Isso reduz drasticamente o boilerplate code (código repetitivo) quando precisamos aplicar a mesma funcionalidade (como auditoria) a diferentes tipos de serviços.
E. Resumo
- Gerenciamento de Memória: O uso de Interfaces é obrigatório para este padrão no Delphi moderno. A contagem de referência garante que, ao destruir o decorador externo, toda a cadeia seja liberada automaticamente.
- Overhead de Indireção: Embora cada camada adicione uma chamada de método virtual, o compilador do Delphi 13 é altamente otimizado. O custo é medido em nanosegundos e é irrelevante frente aos ganhos de manutenibilidade.
- Referências Circulares: Em estruturas complexas, use o atributo
[Weak]se o objeto interno precisar referenciar seu decorador, evitando vazamentos de memória. - Decoradores Genéricos: No Delphi 13, você pode usar Generics para criar decoradores de Log ou Auditoria que funcionam com qualquer interface, reduzindo drasticamente o boilerplate code.
Referências
FLICK, Stefan. Design Patterns with Delphi: Build enterprise-grade applications with modern Delphi and the right design patterns. 1. ed. Birmingham: Packt Publishing, 2024.
GAMMA, Erich; HELM, Richard; JOHNSON, Ralph; VLISSIDES, John. Padrões de Projeto: Soluções reutilizáveis de software orientado a objetos. 1. ed. Porto Alegre: Bookman, 2000.
MARTIN, Robert C. Arquitetura Limpa: O guia do artesão para estrutura e design de software. 1. ed. Rio de Janeiro: Alta Books, 2019.
NOGUEIRA, Rodrigo. Delphi e Clean Architecture: Princípios e práticas para software escalável. 2. ed. São Paulo: Editora Engenharia de Software, 2025.
TEIXEIRA, Marcello. Delphi High Performance: Build fast Delphi applications using concurrency, parallel programming and memory management. 1. ed. Birmingham: Packt Publishing, 2018.
Descubra mais sobre Régys Borges da Silveira
Assine para receber nossas notícias mais recentes por e-mail.
Dê-nos sua opinião, seu comentário ajuda o site a crescer e melhorar a qualidade dos artigos.