Tecnologia além do código.
Régys Borges da Silveira
← Voltar para explorar os artigos

Design Patterns em Delphi 13: Facade e Proxy – Simplicidade e Controle

Neste artigo 15 tópicos

À medida que um projeto Delphi cresce, é natural que o número de classes, units e componentes aumente drasticamente. O problema surge quando a camada de interface (UI) ou outras partes do sistema precisam interagir com dezenas de classes apenas para realizar uma tarefa simples, como emitir uma nota fiscal ou processar um fechamento de caixa. Sem os padrões adequados, o seu código vira um emaranhado de dependências.

Neste artigo, vamos aprender como o Facade simplifica o caos e como o Proxy atua como um intermediário inteligente no Delphi 13.

1. Facade: Domando a Complexidade do Subsistema

O padrão Facade fornece uma interface unificada para um conjunto de interfaces em um subsistema. Ele define uma interface de nível mais alto que torna o subsistema mais fácil de usar.

O Problema: Acoplamento com Múltiplas Units

Imagine que para realizar uma venda, seu formulário precise instanciar: TEstoque, TFinanceiro, TNotaFiscal, TEmailService e TLog.

  • Modo Antigo: O OnClick do botão tem 50 linhas apenas configurando esses objetos.
  • Modo Clean Code (Delphi 13): Você cria uma classe TVendaFacade. O formulário chama apenas VendaFacade.FinalizarVenda(Dados).

A Transição Técnica: O Facade não “esconde” as classes do subsistema de forma que elas fiquem inacessíveis, mas oferece um atalho para as tarefas mais comuns. No Delphi 13, isso reduz drasticamente o uses das suas Units de interface.

2. Proxy: O Intermediário Inteligente

O padrão Proxy fornece um substituto ou um marcador de lugar para outro objeto para controlar o acesso a ele. No Delphi 13, ele é vital para Lazy Loading, controle de permissões e log de auditoria.

Implementação Técnica: Proxy de Proteção e Virtual Proxy

Um uso clássico no dia a dia é o carregamento de imagens pesadas ou relatórios que consomem muita memória.

unit Regys.Patterns.Proxy;

interface

type
  // Interface comum para o Proxy e o Objeto Real
  IServicoRelatorio = interface
    ['{F1E2D3C4-B5A6-4789-B0C1-D2E3F4A5B6C7}']
    procedure GerarRelatorio;
  end;

  // O Objeto Real (Pesado e Caro)
  TRelatorioPesado = class(TInterfacedObject, IServicoRelatorio)
  public
    constructor Create;
    procedure GerarRelatorio;
  end;

  // O Proxy (Leve, controla o acesso)
  TRelatorioProxy = class(TInterfacedObject, IServicoRelatorio)
  private
    FRelatorioReal: IServicoRelatorio;
    FUsuarioTemPermissao: Boolean;
  public
    constructor Create(const ATemPermissao: Boolean);
    procedure GerarRelatorio;
  end;

implementation

{ TRelatorioPesado }
constructor TRelatorioPesado.Create;
begin
  // Simula um carregamento de 5 segundos de dados do banco
  Sleep(5000); 
end;

procedure TRelatorioPesado.GerarRelatorio;
begin
  Writeln('Relatório gerado com sucesso.');
end;

{ TRelatorioProxy }
constructor TRelatorioProxy.Create(const ATemPermissao: Boolean);
begin
  FUsuarioTemPermissao := ATemPermissao;
end;

procedure TRelatorioProxy.GerarRelatorio;
begin
  if not FUsuarioTemPermissao then
    raise Exception.Create('Acesso negado!');

  // Lazy Initialization (Virtual Proxy): Só cria o objeto caro se necessário
  if not Assigned(FRelatorioReal) then
    FRelatorioReal := TRelatorioPesado.Create;

  FRelatorioReal.GerarRelatorio;
end;

end.

3. Aplicação no Dia a Dia: Blindando o Core do Sistema

No cotidiano de um desenvolvedor Delphi 13, a aplicação estratégica destes padrões separa sistemas frágeis de arquiteturas resilientes. Enquanto o Facade simplifica a “conversa” entre camadas, o Proxy garante que essa conversa só aconteça sob as condições certas.

A. Facade como Orquestrador de Integrações (Fiscal e Bancária)

Um dos cenários mais comuns no ecossistema Delphi é o uso de componentes gigantescos, como o ACBr ou bibliotecas de boletos.

  • Cenário de Uso: Para emitir uma NF-e, você precisa configurar emitente, destinatário, itens, impostos, certificados e protocolos de envio.
  • Transição Clean: Em vez de poluir seu TService ou TForm com centenas de linhas de configuração de componentes, você cria um TFiscalFacade.
  • Resultado: Seu sistema chama apenas FiscalFacade.Emitir(VendaId). Se amanhã você precisar trocar o componente de emissão ou migrar para uma API em nuvem, o impacto no seu código de negócio é zero. O Facade isola a volatilidade das ferramentas externas.

B. Proxy de Proteção: Segurança e Regras de Acesso

Em sistemas ERP complexos, nem todo usuário pode executar todas as operações, mas espalhar if Usuario.Perfil = 'Gerente' por todo o código é um erro clássico de manutenção.

  • Uso Prático: Implementamos um Proxy que envolve a classe de negócio. Antes de delegar a chamada para o objeto real, o Proxy consulta o serviço de permissões.
  • Vantagem: A classe real foca apenas na regra de negócio (SRP), enquanto o Proxy foca na segurança. Isso facilita auditorias e mudanças nas políticas de acesso sem tocar no código core.

C. Virtual Proxy para Performance em Grids e Dashboards

O Delphi 13 é excelente para lidar com grandes volumes de dados, mas carregar objetos pesados (como fotos de produtos ou históricos de transações) para mil registros de uma vez causará lentidão e consumo excessivo de memória.

  • Implementação no Delphi 13: Utilizamos um Virtual Proxy dentro de um TObjectList. O objeto na lista é o Proxy; ele é leve e contém apenas o ID. Quando a UI solicita o campo Foto ou Historico, o Proxy verifica se o objeto real já foi carregado. Caso contrário, ele busca no banco (Lazy Loading) no exato momento da demanda.

D. Proxy de Log e Auditoria (Observabilidade)

Com o aumento da necessidade de conformidade (LGPD), rastrear quem alterou o quê é vital. Um Proxy de Auditoria pode interceptar chamadas aos métodos de persistência, registrando o estado anterior e o novo estado do objeto de forma automática e transparente para o restante do sistema.

4. Nuances Técnicas: Memória e Transparência no Delphi 13

Implementar Facades e Proxies no Delphi 13 não se resume a criar classes intermediárias; trata-se de gerenciar o ciclo de vida dos objetos de forma que o padrão não se torne um fardo para o hardware.

A. Ownership e Ciclo de Vida no Facade

O Facade, por definição, orquestra múltiplos subsistemas. No Delphi 13, a decisão crítica é: o Facade é o “dono” (owner) dos objetos que ele utiliza?

  • Recomendação: Se o Facade instancia classes concretas (como um TFDConnection ou um TACBrPosPrinter), ele deve obrigatoriamente implementar o destructor Destroy para liberar esses recursos.
  • Abordagem Moderna: Utilize o Facade retornando Interfaces. Isso permite que o Facade gerencie a criação, mas o Delphi gerencie a destruição via contagem de referência, simplificando o uso por parte do desenvolvedor da UI.

B. Transparência do Proxy e o Custo da Indireção

Para que um Proxy seja eficaz, ele deve ser indistinguível do objeto real. No Delphi 13, isso é alcançado através de Interfaces.

  • Performance: Muitos temem que a camada extra do Proxy degrade a performance. Contudo, o custo de uma chamada de método via Interface é insignificante (nanosegundos). O verdadeiro ganho de performance vem do Virtual Proxy: ao evitar a criação de um objeto de 10MB que o usuário nunca chegaria a abrir, você economiza muito mais recursos do que o custo da indireção.

C. Gerenciamento de Memória em Lazy Loading (Proxy)

O maior risco em um Proxy de carregamento tardio (Lazy Loading) no Delphi 13 é o vazamento de memória se o objeto real for criado mas nunca liberado.

  • Técnica Sênior: Se o seu Proxy for um TInterfacedObject, a referência ao objeto real deve ser armazenada em um campo privado que implemente a mesma interface. Dessa forma, quando o Proxy morre, a referência do objeto real cai para zero e ele também é liberado.
  • Atenção: Se o objeto real for uma classe pura (TObject), o Proxy precisa dar o Free nele manualmente no seu próprio Destroy.

D. Concorrência e Thread Safety no Delphi 13

Em aplicações multithread (como servidores REST), um Proxy que faz Lazy Loading pode sofrer de Race Conditions.

  • Solução: No Delphi 13, utilize o TMonitor.Enter(Self) ou TCriticalSection dentro do Proxy para garantir que, se duas threads tentarem acessar o recurso pesado simultaneamente, o objeto real seja instanciado apenas uma vez com segurança.

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.

Compartilhar por e-mail

0 comentário(s)

Dê-nos sua opinião, seu comentário ajuda o site a crescer e melhorar a qualidade dos artigos.

Este site utiliza o Akismet para reduzir spam. Saiba como seus dados em comentários são processados.

Um próximo passo para cada interesse.

Continue estudando com os livros, acompanhe as videoaulas ou consulte as soluções para o seu projeto.

Descubra mais sobre Régys Borges da Silveira

Assine agora mesmo para continuar lendo e ter acesso ao arquivo completo.

Continuar lendo