Sempre quis saber como usar a Injeção de Dependência com Delphi? Eu criei um exemplo para você no qual passamos de um código fortemente acoplado a um belo código desacoplado em algumas etapas através da Injeção de Dependência e com a ajuda de interfaces.
Vamos começar com o exemplo a seguir:
unit DI1; interface type TLanguageTools = class private procedure CheckGrammar; procedure Translate; end; TWordApp = class private FLanguageTools: TLanguageTools; public constructor Create; end; implementation constructor TWordApp.Create; begin FLanguageTools := TLanguageTools.Create; FLanguageTools.Translate; end; { TLanguageTools } procedure TLanguageTools.CheckGrammar; begin // end; procedure TLanguageTools.Translate; begin // end; end.
Como você pode ver, não há nada de errado com o código em princípio. É um código Delphi válido e funciona. No entanto, há algumas observações a serem feitas. Primeiro de tudo, o código é fortemente acoplado; a classe TWordApp não só depende da classe TLanguageTools, mas você não pode nem mesmo estender a classe TLanguageTools com funcionalidade extra. Mesmo que você substitua a classe TLanguageTools com, por exemplo, TEnglishLanguageTools, TWordApp simplesmente usa a classe base TLanguageTools.
Podemos fazer melhor do que isso! Uma primeira grande melhoria é remover a dependência do construtor Criar, e injetá-la. Injetar uma dependência pode ser feito de várias maneiras, através de propriedades, procedimentos ou construtores. Neste exemplo, eu uso o construtor. O código abaixo já tem uma dependência um pouco mais frouxa entre as duas classes:
unit DI2; interface type TLanguageTools = class private procedure CheckGrammar; procedure Translate; end; TWordApp = class private FLanguageTools: TLanguageTools; public constructor Create(ALanguageTools: TLanguageTools); end; implementation constructor TWordApp.Create(ALanguageTools: TLanguageTools); begin FLanguageTools := ALanguageTools; FLanguageTools.Translate; end; { TLanguageTools } procedure TLanguageTools.CheckGrammar; begin // end; procedure TLanguageTools.Translate; begin // end; end.
Como você pode ver no exemplo, ainda estamos usando a classe TLanguageTools. Entretanto, agora é possível substituir esta classe TLanguageTools, e dar esta nova classe à classe TWordApp. E na verdade, esta é a base da classe Dependency Injection. Seu código é muito mais frouxamente acoplado e reutilizável.
Usando interfaces, podemos ir um passo além. É possível descrever a funcionalidade da classe TLanguageTools em diferentes interfaces, e passá-la para a classe TWordApp. Desta forma, programamos contra abstrações, e não contra implementações.
unit DI3; interface type IGrammarChecker = interface ['{FED7BA76-0EDE-40E7-BABB-16BCFE76F6DF}'] procedure CheckGrammar; end; ITranslator = interface ['{C1F1092F-3589-49E5-8F22-33E8D7587A8B}'] procedure Translate; end; TLanguageTools = class(TInterfacedObject, IGrammarChecker, ITranslator) private procedure CheckGrammar; procedure Translate; end; TWordApp = class private FTranslator: ITranslator; public constructor Create(ATranslator: ITranslator); end; implementation constructor TWordApp.Create(ATranslator: ITranslator); begin FTranslator := ATranslator; FTranslator.Translate; end; procedure TLanguageTools.CheckGrammar; begin // end; procedure TLanguageTools.Translate; begin // end; end.
Como você pode ver, a classe TWordApp não depende mais da classe TLanguageTools. Desde que passemos para o construtor uma instância com uma implementação da interface do ITranslator, o código apenas funcionará. Não precisamos mais nem mesmo da classe TLanguageTools.
Assim, com a ajuda da Injeção de Dependência e com interfaces, obtemos um código de fonte agradável, desacoplado e bem conservado.
Torne-se um herói da GDK Delphi! Subscreva aqui para nossa lista de correio da Delphi!
Contato