Já foram feitas várias perguntas com perguntas específicas sobre injeção de dependência, como quando utilizá-la e que estruturas existem para ela. No entanto,
O que é injeção de dependência e quando/por que deve ou não deve'não deve ser usado?
A melhor definição que encontrei até agora é one by James Shore:
"Injeção de Dependência" é uma injeção de 25 dólares termo para um conceito de 5 cêntimos. [...] injeção de dependência significa dar um objetar suas variáveis de instância. [...].
Há um artigo de Martin Fowler que pode ser útil, também.
A injeção de dependência é basicamente fornecer os objetos que um objeto precisa (suas dependências) em vez de tê-los construídos por ele mesmo. É uma técnica muito útil para testes, já que permite que as dependências sejam ridicularizadas ou excluídas.
Dependências podem ser injetadas em objetos por muitos meios (como injeção de construtor ou injeção de setter). Pode-se até usar estruturas especializadas de injeção de dependência (por exemplo, mola) para fazer isso, mas certamente não são necessárias. Você não precisa dessas estruturas para ter a injeção de dependência. Instanciar e passar objetos (dependências) explicitamente é uma injeção tão boa quanto a injeção por estrutura.
Injeção de dependência está passando dependência para outros objetos ou **quadro***( injetor de dependência).
A injecção de dependência facilita os testes. A injeção pode ser feita através de **construtor***.
SomeClass()
tem o seu construtor como o seguinte:
public SomeClass() {
myObject = Factory.getObject();
}
Problema:
Se o myObject
envolve tarefas complexas, como acesso a disco ou acesso à rede, é duro fazer teste de unidade em SomeClass()
. Os programadores têm que fazer um mock do myObject
e podem interceptar a chamada de fábrica.
**Solução alternativa***:
myObject
como argumento para o construtorpublic SomeClass (MyClass myObject) {
this.myObject = myObject;
}
O "myObject" pode ser aprovado diretamente, o que facilita os testes.
É mais difícil isolar componentes em testes unitários sem injeção de dependência.
Em 2013, quando escrevi esta resposta, este foi um tema importante no Google Testing Blog. Continua a ser a maior vantagem para mim, pois os programadores nem sempre precisam da flexibilidade extra em seu design de tempo de execução (por exemplo, para localização de serviços ou padrões similares). Os programadores muitas vezes precisam isolar as aulas durante os testes.
A injeção de dependência é uma prática onde os objetos são projetados de forma que recebam instâncias dos objetos de outras peças de código, em vez de construí-los internamente. Isto significa que qualquer objeto implementando a interface que é requerida pelo objeto pode ser substituída sem alterar o código, o que simplifica os testes e melhora o desacoplamento.
Por exemplo, considere estas clases:
public class PersonService {
public void addManager( Person employee, Person newManager ) { ... }
public void removeManager( Person employee, Person oldManager ) { ... }
public Group getGroupByManager( Person manager ) { ... }
}
public class GroupMembershipService() {
public void addPersonToGroup( Person person, Group group ) { ... }
public void removePersonFromGroup( Person person, Group group ) { ... }
}
Neste exemplo, a implementação de PersonService::addManager' e
PersonService::removeManager' precisaria de uma instância do GroupMembershipService' para poder fazer seu trabalho. Sem a Injeção de Dependência, a forma tradicional de fazer isso seria instanciar um novo
GroupMembershipService' no construtor do PersonService' e utilizar esse atributo de instância em ambas as funções. Entretanto, se o construtor do
GroupMembershipService' tem várias coisas que requer, ou pior ainda, existem alguns "setters" de inicialização que precisam ser chamados no GroupMembershipService', o código cresce rapidamente, e o
PersonService' agora depende não apenas do GroupMembershipService', mas também de tudo mais que o
GroupMembershipService' depende. Além disso, a ligação com o GroupMembershipService' é codificada em código rígido no
PersonService', o que significa que você não pode "falsificar" um `GroupMembershipService' para fins de teste, ou para utilizar um padrão de estratégia em diferentes partes da sua aplicação.
Com a Injeção de Dependência, ao invés de instanciar o GroupMembershipService' dentro do seu
PersonService', você o passaria para o construtor do PersonService', ou então adicionaria uma Propriedade (getter and setter) para definir uma instância local da mesma. Isto significa que seu
PersonService' não precisa mais se preocupar em como criar um GroupMembershipService', ele apenas aceita os que lhe são dados, e trabalha com eles. Isto também significa que qualquer coisa que seja uma subclasse do
GroupMembershipService', ou implemente a interface do GroupMembershipService', pode ser "injetada" no
PersonService', e o `PersonService' não precisa saber sobre a mudança.