Exemplo-TInterfacedObject-Acoplamento
- Active · last change 6-29-2026
- ★ 1 on GitHub
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:
// 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
TRelatorioManualparaTRelatorioPDFexige editar o form. try/finally + Freeespalhado 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:
// 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, semtry/finally—TInterfacedObjectgerencia o tempo de vida. - Mock pode substituir a factory em testes sem tocar no form.
Estrutura do projeto
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??rioCamadas de dependência
frmPrincipal ??? Relatorio.Contrato (interface)
???
Relatorio.PDF Relatorio.CSV Relatorio.MockO 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:
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:
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; // restauraExecutar
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 |

