Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Catalog · How the catalog works
Anything · Lazarus or Delphi
Random projectRandom project

Exemplo-TInterfacedObject-Acoplamento

View on GitHub

Member rating

No ratings yet.

Sign in to rate this project.

README

Acoplamento vs Desacoplamento em Delphi

Exemplo prático que demonstra a diferença entre alto acoplamento (classe concreta exposta) e baixo acoplamento (dependência via interface) usando TInterfacedObject em Delphi/Pascal.


O problema: alto acoplamento

Quando um form depende diretamente de uma classe concreta, ele precisa conhecer o tipo exato, gerenciar a memória manualmente e mudar sempre que a implementação muda:

pascal
// frmPrincipal conhece TRelatorioManual — acoplado ao detalhe
uses SemInterface;

var lRel: TRelatorioManual;
begin
  lRel := TRelatorioManual.Create('Vendas');
  try
    lRel.Gerar;
  finally
    lRel.Free;  // responsabilidade do consumidor — esquecer = vazamento
  end;
end;

Problemas:

  • Trocar de TRelatorioManual para TRelatorioPDF exige editar o form.
  • try/finally + Free espalhado em todo consumidor.
  • Impossível testar sem instanciar a classe real.

A solução: baixo acoplamento via interface

O form declara dependência apenas do contrato (IRelatorio). A implementação concreta é injetada por uma factory — o form não sabe se é PDF, CSV ou Mock:

pascal
// frmPrincipal só vê Relatorio.Contrato — desacoplado
uses Relatorio.Contrato, Relatorio.Abstracao;

var lRel: IRelatorio;
begin
  lRel := NovoRelatorio('Vendas');  // factory decide qual classe criar
  lRel.Gerar;
  // Destroy chamado automaticamente ao sair de escopo (ARC via TInterfacedObject)
end;

Ganhos:

  • Trocar PDF por CSV é uma linha na dpr (composition root).
  • Sem Free, sem try/finally — TInterfacedObject gerencia o tempo de vida.
  • Mock pode substituir a factory em testes sem tocar no form.

Estrutura do projeto

pascal
Relatorio.Contrato   ??? s?? interfaces (IRelatorio, IExportavel) ??? zero depend??ncia concreta
Relatorio.Abstracao  ??? factory global (NovoRelatorio) ??? composition root plug??vel
Relatorio.PDF        ??? TRelatorioPDF: TInterfacedObject, IRelatorio, IExportavel
Relatorio.CSV        ??? TRelatorioCSV: TInterfacedObject, IRelatorio
Relatorio.Mock       ??? TRelatorioMock: para testes, grava se Gerar foi chamado
SemInterface         ??? TRelatorioManual: TObject puro, exige Free manual
ComInterface         ??? vers??o inline com IRelatorio+TRelatorio num ??nico arquivo
uLog                 ??? callback de log ??? Writeln no console, Memo no Form
uPrincipal           ??? Form VCL com 4 bot??es demonstrando cada cen??rio

Camadas de dependência

pascal
frmPrincipal ??? Relatorio.Contrato (interface)
                      ???
     Relatorio.PDF  Relatorio.CSV  Relatorio.Mock

O form nunca importa Relatorio.PDF diretamente — essa é a essência do desacoplamento.


Herança múltipla via interface

TRelatorioPDF implementa dois contratos independentes. O consumidor obtém a segunda visão com Supports — sem downcast, sem conhecer o tipo concreto:

pascal
if Supports(lRel, IExportavel, lExp) then
  lExp.Exportar;

Testabilidade via factory substituível

A factory CriarRelatorio é uma variável de função — pode ser trocada em runtime para injetar um mock sem frameworks:

pascal
CriarRelatorio :=
  function(const pNome: string): IRelatorio
  begin
    Result := lMockRef;   // mock no lugar da implementação real
  end;

NovoRelatorio('Teste').Gerar;
Assert(lMock.GerouChamado, 'Mock nao foi chamado');

CriarRelatorio := lSalvo;  // restaura

Executar

Abra InterfaceVCL.dproj no Delphi e rode. Os 4 botões demonstram:

Botão O que mostra
Acoplado TRelatorioManual — try/finally + Free obrigatório
Desacoplado IRelatorio via factory — ARC, sem Free, sem conhecer PDF/CSV
Limpar Limpa o Memo
Teste/Mock Factory substituída por TRelatorioMock — costura testável