Este é um post disponível para assinantes MVPInversão de Controle e Injeção de Dependência - Revista ClubeDelphi 133
Este artigo mostra o que é e como usar inversão de controle e a injeção de dependência. Você aprenderá na prática, através de um exemplo, como estes princípios de programação orientada a objetos podem ser usados e qual as vantagens que eles traz
[Artigo já está disponível no Leitor Digital DevMedia®. Clique aqui para acessá-lo]
> Clique aqui para ler todos os artigos da ClubeDelphi 133
Diz-se que um
projeto está altamente acoplado quando suas classes e módulos conhecem muito um
do outro, criando uma grande dependência entre eles. Isto acontece, na maioria
das vezes, devido a uma decisão errada, tomada pelo projetista, que aos pouco
encaminha o projeto para um design caótico onde uma simples manutenção de
rotina pode desencadear uma série de erros em outro ponto do projeto.
O grande vilão, que
pode tornar uma alteração pequena em um verdadeiro desastre é o relacionamento
entre as classes, por isso é vantajoso investir o tempo necessário (ou possível),
para criar designs onde as classes sejam capazes de se relacionar conhecendo o mínimo
uma da outra. Criar classes coerentes que dependem apenas de interfaces é uma
das formas de garantir o baixo acoplamento, porém o princípio “programe para
interface”, sozinho não ajudará muito.
O problema do alto
acoplamento
Podemos medir o quão fortemente as classes de uma aplicação estão conectadas, possuem conhecimento ou dependem de outra classe observando o acoplamento existente em cada caso. Quanto mais acoplada uma classe estiver de outra maior o risco de termos uma combinação dos seguintes problemas:
· Mudanças numa classe relacionada forçam alterações locais à classe para que o funcionamento seja mantido;
· O reuso da classe torna-se mais difícil uma vez que sua implementação depende de outras classes;
· A coesão da classe diminui na medida em que aumenta o acoplamento caso ela assuma parte das responsabilidades de outra classe;
· A classe não pode ser testada isoladamente já que depende de testes em conjunto com outras classes, aumentando inclusive o esforço de entendimento.
Percebemos rapidamente que diminuindo ao máximo o acoplamento além de evitarmos os problemas mencionados anteriormente tornaremos nossa aplicação mais flexível e fácil de ser mantida, especialmente em equipes com paralelismo de desenvolvimento de atividades correlatas.
Utilizando as corretas técnicas e ferramentas para injeção de dependência, diversos componentes podem ser desenvolvidos paralelamente (aproveitando de recursos como Mock Objects para auxiliar nos testes unitários) e sua aplicação se tornará mais plugável e flexível, exigindo um esforço menor para modificações.
Técnicas para
resolver o problema de alto acoplamento
Tomemos como exemplo uma classe chamada ClasseA que depende dos serviços Servico1 e Servico2, conforme a Figura 1.
Se em algum momento necessitarmos substituir ou atualizar alguma das suas dependências, a classe ClasseA sofrerá alterações em seu código, uma vez que está relacionada diretamente com as classes de serviço. Outro ponto é que as implementações concretas das dependências precisam estar disponíveis no momento da compilação da solução. Uma das soluções seria delegar a função de selecionar a implementação da classe concreta para um componente (ou um container) externo.
Em diversas literaturas podemos encontrar esta solução sendo descrita como Padrão de Inversão de Controle (Inversion of Control Pattern, ou simplesmente IoC), onde a Injeção de Dependência é uma das maneiras de a implementarmos (assim como o Service Locator Pattern), conforme observamos na Figura 2. Sendo assim, é correto afirmarmos que a DI é um caso particular de IoC.
A classe ClasseA ao
invés de fazer referência à classe concreta passa a referenciar uma interface
IServicoA que por sua vez é implementada pelo serviço Servico1, o objeto
identificado como Builder fica encarregado de resolver a classe concreta e
injetar a dependência na classe ClasseA.
Também é importante e necessário, que o projetista saiba como usar uma interface corretamente e para isto ele pode recorrer aos padrões de projetos. A maioria dos padrões de projetos usa interfaces e definem classes coerentes com baixa coesão para solucionar os problemas que se propõem a resolver. Mesmo assim, existem decisões, cujas respostas o projetista não vai encontrar em um padrão de projeto. Por exemplo: é melhor criar uma interface usando uma classe abstrata ou uma interface de fato? A resposta não é tão obvia quanto parece.
Outra forma de
diminuir o acoplamento é a inversão de controle ou em inglês Inversion of
Control (IoC). Inversão de controle é um princípio de orientação de objetos que
define várias formas de simplificar um projeto invertendo o controle natural
dos componentes. Existe mais de uma forma de inversão de controle: umas delas é
a injeção de dependência.
A injeção de dependência
ou em inglês dependency injection (DI), significa que uma classe não deve
controlar as suas dependências, evidentemente tornando o projeto mais flexível.
Nesta abordagem uma classe recebe suas dependências sem conhecer como elas são
criadas ou de onde elas vêm. Pode parecer estranho para quem está escutando
isto pela primeira vez, mas é isto mesmo que você leu. De forma superficial a
injeção de dependência pode ser explicada assim: se a classe A precisa da
classe B, então A não deve executar B.Create().
Como dito, existem
outras formas de inversão de controle além da injeção de dependência. Outro
exemplo disto está na própria VCL. Quando você cria um formulário e escreve
qualquer instrução no evento OnCreate do mesmo, você está usando a inversão de
controle, pois não é você quem controla a execução das instruções que você
escreveu no evento, mas sim o framework, que neste caso é a VCL. É o framework
que decide quando executar o código, e não o contrário.
Tipos de relacionamentos e o que eles têm a ver com DI
A técnica de injeção
de dependência atua diretamente na forma como as classes e objetos se
relacionam dentro de um projeto, por isto este tópico é dedicado a explicar
quais sãos os tipos de relacionamentos existentes e a diferença entre eles.
Você pode pular para o próximo tópico se estiver familiarizado aos jargões
composição/agregação e já sabe por que dar preferência a eles é (quase sempre)
melhor do que criar um relacionamento do tipo herança.
ATENÇÃO! A exibição deste artigo foi interrompida.
Este é um post disponível para assinantes MVP
1 COMENTÁRIO
Space do autor


1
0
