Como desenvolvedores Delphi, frequentemente lidamos com dois desafios arquiteturais: representar estruturas de árvore (como menus, organogramas ou composições de produtos) e evitar a explosão de classes quando uma funcionalidade precisa rodar em múltiplas plataformas ou bancos de dados.
Neste artigo, veremos como o Composite nos permite tratar objetos individuais e composições de forma uniforme, e como o Bridge desata o nó entre o “o que o objeto faz” e “como ele é implementado” no Delphi 13.
1. Composite: A Unificação de Partes e Todo
O padrão Composite é utilizado para compor objetos em estruturas de árvore. Ele permite que os clientes tratem objetos individuais e composições de objetos de maneira idêntica.
O Problema: Tratamento Diferenciado para Grupos e Itens
Imagine um sistema de vendas onde um “Item” pode ser um produto simples ou um “Kit” contendo vários produtos.
- Modo Antigo: Você precisa de
ifsconstantes para verificar se está lidando com umTProdutoou umTKit. O código de cálculo de preço torna-se complexo e difícil de manter. - Modo Moderno (Delphi 13): Tanto o produto quanto o kit implementam a mesma interface
IComponente. O Kit armazena uma lista deIComponente, permitindo chamadas recursivas transparentes.
A Transição Técnica: O Composite elimina a necessidade de o cliente conhecer a estrutura interna da árvore. Se você chamar GetPreco, o componente individual retorna seu valor, enquanto o composto percorre seus filhos e soma os resultados, tudo de forma polimórfica.
2. Bridge: Separando a Abstração da Implementação
O padrão Bridge foca na “desconexão”. Ele separa uma abstração de sua implementação, permitindo que ambas variem independentemente. No Delphi 13, isso é essencial para sistemas que suportam múltiplos drivers de banco de dados ou engines de renderização.
Implementação Técnica: Evitando a Explosão de Subclasses
Se você tem uma classe TRelatorio e precisa de versões PDF e HTML para Windows e Linux, a herança tradicional exigiria 4 subclasses. Com o Bridge, você tem a hierarquia de Relatórios (Abstração) e a hierarquia de Renderizadores (Implementação).
unit Regys.Patterns.Bridge;
interface
type
// 1. A Implementação (O "Como")
IRenderizador = interface
['{C1D2E3B4-A5F6-4789-B0C1-D2E3F4A5B6C7}']
procedure RenderizarTexto(const ATexto: string);
end;
// 2. A Abstração (O "O Que")
TRelatorio = class
protected
FRender: IRenderizador;
public
constructor Create(const ARender: IRenderizador);
procedure Gerar; virtual; abstract;
end;
// 3. Abstração Refinada
TRelatorioVendas = class(TRelatorio)
public
procedure Gerar; override;
end;
// 4. Implementador Concreto
TRenderPDF = class(TInterfacedObject, IRenderizador)
public
procedure RenderizarTexto(const ATexto: string);
end;
implementation
{ TRelatorioVendas }
constructor TRelatorio.Create(const ARender: IRenderizador);
begin
FRender := ARender;
end;
procedure TRelatorioVendas.Gerar;
begin
FRender.RenderizarTexto('Relatório de Vendas Gerado');
end;
{ TRenderPDF }
procedure TRenderPDF.RenderizarTexto(const ATexto: string);
begin
// Lógica específica para gerar PDF no Delphi 13
end;
end.
3. Aplicação no Dia a Dia: Flexibilidade e Estruturas Recursivas
No cotidiano de um arquiteto Delphi 13, o Composite e o Bridge são frequentemente utilizados em conjunto para resolver problemas de escala e multiplataforma. Enquanto um organiza a estrutura interna dos dados, o outro protege o sistema contra mudanças nas APIs externas ou de hardware.
A. Composite: Menus, Permissões e Árvores de Produtos
O uso mais prático do Composite no Delphi ocorre quando precisamos gerenciar estruturas onde um “item” pode ser, na verdade, um “grupo de itens”.
- Cenário de Uso (ERPs): Imagine um sistema de permissões de acesso. Você tem “Permissões Simples” (ex: Ler, Escrever) e “Grupos de Permissões” (ex: Gerente, Operador).
- Transição Clean: Ao tratar ambos como
IPermissao, o seu métodoUsuario.TemAcesso(IPermissao)funciona de forma recursiva. Se o usuário tentar acessar uma permissão que é um Grupo, o Composite percorre todos os filhos automaticamente. - Resultado: Você elimina loops
fore verificações de tipo (is/as) espalhados pelo código, centralizando a lógica de travessia na classe composta.
B. Bridge: O Escudo contra a Explosão de Subclasses Multiplataforma
O Bridge é o padrão “salva-vidas” para desenvolvedores que precisam manter um core único para Windows (VCL) e Android/iOS (FMX), ou para sistemas que suportam múltiplos motores de banco de dados.
- Exemplo Real: Suponha que você tenha uma classe de
TEmissorBoleto. Se você precisar emitir boletos via API REST e também via componentes locais (como FastReport), a herança criaria um nó górdio. - A Solução com Bridge: Você separa a Abstração (
TBoleto) da Implementação (IProvedorEmissao). - Vantagem: Você pode adicionar um novo banco ou um novo layout de impressão apenas criando uma nova implementação da interface, sem nunca tocar na regra de negócio que calcula juros e multas.
C. Composição em Engines de Relatórios e UI
No Delphi 13, ao construir componentes visuais complexos ou geradores de documentos, o Composite permite que você trate cada “quadro”, “linha” ou “campo” como um nó de uma árvore. Isso facilita a implementação de funcionalidades como “Esconder Grupo” ou “Calcular Soma do Grupo”, pois a chamada é propagada naturalmente pela árvore de objetos, respeitando a hierarquia visual.
D. Bridge para Persistência e Drivers (FireDAC/REST)
Muitas software houses estão migrando de Client/Server para Multi-tier. O Bridge permite que sua aplicação utilize um TDataBridge que pode ser configurado para usar um TLocalDriver (FireDAC direto no banco) ou um TRemoteDriver (chamadas REST/JSON), permitindo que o mesmo executável funcione em cenários de rede local ou nuvem apenas trocando a implementação injetada.
4. Nuances Técnicas: Performance e Gerenciamento de Árvores no Delphi 13
Implementar os padrões Composite e Bridge no Delphi 13 exige mais do que apenas criar classes e interfaces; exige um entendimento de como o compilador gerencia recursividade e instâncias automáticas.
A. Recursividade e a Pilha (Stack Overflow) no Composite
O padrão Composite baseia-se fortemente em chamadas recursivas para percorrer árvores. No Delphi 13, embora o limite da stack seja generoso, árvores extremamente profundas (milhares de níveis) podem causar um Stack Overflow.
- Técnica Sênior: Se a sua estrutura for muito profunda, considere implementar a travessia usando um padrão Iterator ou uma pilha manual (
TStack<T>) para transformar a recursão em uma iteração, protegendo a estabilidade da aplicação.
B. Gestão de Memória em Estruturas de Árvore
O maior desafio do Composite é garantir que, ao destruir um “Nó Pai”, todos os “Filhos” sejam liberados.
- Solução Moderna: No Delphi 13, utilize
TList<IInterface>ouTInterfaceListpara armazenar os filhos. Graças à contagem de referência, quando o pai é liberado e a lista interna é destruída, a referência dos filhos cai para zero e eles são limpos automaticamente. - Atenção: Evite referências circulares (um filho que aponta para o pai). Se for necessário que o filho conheça o pai, use o atributo
[Weak]no campo que armazena o pai para evitar vazamentos de memória (Memory Leaks).
C. O Custo da Indireção no Bridge
O Bridge introduz uma camada extra de indireção (Abstração -> Implementação). No Delphi 13, isso significa uma chamada adicional através de uma interface ou ponteiro de método.
- Impacto Real: Em 99% das aplicações empresariais, esse custo é irrelevante. No entanto, em loops críticos de alta performance (como processamento de milhares de pixels ou cálculos matemáticos intensos), essa indireção pode ser notada.
- Otimização: Avalie se a implementação pode ser injetada uma única vez no início do processo para evitar resoluções constantes de interface dentro de loops pesados.
D. Injeção de Dependência no Bridge
Para que o Bridge seja verdadeiramente eficaz no Delphi 13, a Abstração não deve instanciar a Implementação concreta.
- Prática Recomendada: Utilize Injeção de Dependência via construtor. Isso permite que você troque o driver de banco ou o engine de relatórios em tempo de execução sem alterar a classe de Abstração, facilitando testes de unidade com Mocks.
E. Resumo
- Recursividade no Composite: No Delphi 13, certifique-se de que a recursividade do Composite tenha um ponto de parada para evitar Stack Overflow em árvores excessivamente profundas.
- Memória em Estruturas Composite: Como o Composite lida com coleções de objetos, o uso de
TInterfaceListouTList<IInterface>é altamente recomendado. Isso garante que, ao destruir o “pai”, todos os “filhos” sejam liberados corretamente via contagem de referência. - Desacoplamento no Bridge: O segredo do Bridge no Delphi 13 é que a Abstração contém uma referência para a Interface da Implementação (Composição). Isso permite que você mude o comportamento do objeto em tempo de execução apenas trocando o objeto de implementação injetado.
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.
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.