Fala pessoal!!!
Com este breve artigo(breve mesmo!) vou falar sobre o conceito de Inversão de Controle, que muitos confundem com Injeção de Dependência. É justo, já que no primeiro momento os dois conceitos são bem parecidos.
O que é a Inversão de Controle (IoC)?
Basicamente, a Inversão de Controle é uma forma diferente que temos para manipular o controle sobre um objeto. É um padrão. Gosto de pensar na Inversão de Controle como sendo a mudança de conhecimento que uma classe tem em relação à outra.
Gosto de ver um trecho teórico com um trecho de código, então vamos ver desta forma!
Vamos imaginar uma classe bem simples, onde precisamos gravar um Log em um arquivo após Vender um Produto. Então podemos ter a seguinte classe bem simples:
public class VendaDeProduto {
public void vendeProduto(Produto produto) {
//Todo o código para a venda do produto...
Log log = new Log("Arquivo.txt");
log.grava(produto);
}
}
Mas qual o problema?
Razoável o exemplo. Uma classe facilmente encontrada em qualquer código. Eu
sou ruim para perceber problemas em uma classe só de vê-la, então vou imaginar uma situação real: Percebemos que
a classe Log precisa do arquivo onde será gravado o Log correto? Agora vamos imaginar que o nome do arquivo
será mudado para "ArquivoLog.txt"! Muito fácil, basta mudar o nome correto? Vamos então abrir a classe VendaDeProduto
e mudar!
Putz! Aqui que está o problema! O que a classe de Venda tem a ver com isso? Na verdade, nada! Ou pelo menos não deveria ter. Para uma modificação na classe Log fomos obrigados a modificar algo dentro da classe de Venda e isso não é legal. Neste momento foi fácil modificar, mas e se tivéssemos 30 classes utilizando a classe Log? Quais as chances de esquecermos uma?
No pequeno exemplo acima vimos um detalhe importante: A classe VendaDeProduto sabe demais sobre a classe Log.
A classe VendaDeProduto sabe criar a classe Log. Pior, a classe de vendas sabe que a classe Log precisa
do nome de um arquivo! E isso não é justo com a classe VendaDeProduto.
A responsabilidade dela é somente
de fechar uma venda. Portanto podemos ver um alto acoplamento de classes neste minúsculo código.
Um problema mais a fundo
Pra você que desenvolve com TDD, como faríamos
por exemplo para fazer um teste com a classe VendaDeProduto quando precisarmos "mocká-la"? Simplesmente
não conseguimos, justamente por ela criar o objeto Log! E não vale você que conhece o PowerMock inventar algo! :)
Resolvendo o problema
É aqui que entra a Inversão de Controle. Vamos literalmente
inverter este controle na classe VendaDeProduto. Em vez de deixarmos a responsabilidade da criação da classe Log para
a classeVendaDeProduto, vamos dar a ela esta dependência. Vamos injetar esta dependência nela. E olha o
que apareceu para nós: Injeção de Dependência.
Daí muitos confundirem e acharem que os dois são a mesma coisa. Como você pode ver, vamos resolver o problema desta classe Invertendo o Controle, utilizando a Injeção de Dependência. Simples assim!
Vamos resumir: Injeção de Dependência é apenas uma forma para resolvermos a Inversão de Controle.
Temos algumas formas interessantes de Injeção de Dependência e vou falar da mais comum(em um próximo post falarei de outras!): O Constructor Injection, ou seja, injetamos uma dependência de uma classe através do construtor desta classe.
Vamos novamente exemplificar este trecho de teoria com um pouco de código. Para sermos mais coerente, vamos melhorar um pouco mais o nosso código anterior, utilizando a Injeção de Dependência!
public class VendaDeProduto { private Log log; public void VendaDeProduto(Log logVenda) { this.log = logVenda; } public void vendeProduto(Produto produto) { //Todo o código para a venda do produto... log.grava(produto); } }
Olha como ficou interessante, elegante e simples! A classe VendaDeProduto precisa da classe Log para criar um Log mas neste código a classe VendaDeProduto recebeu uma instância da classe Log! Ou seja, agora ela não se preocupa mais com a criação da classe Log e simplesmente a usa.
Como a classe Log é criada agora? Não sei! E nem precisamos saber! A única coisa que precisamos é uma instância da classe Log para trabalharmos, independente de como ela foi criada!
Agora pra você que trabalha com TDD ficou muito mais simples pois basta "mockar" a classe Log, passá-la pelo construtor e fazer os testes normais da sua classe!
Finalizando
Desta forma diminuimos o acoplamente entre as nossas classes e a manutenção fica facilitada
e, além de elegante, agora temos uma classe testável. Só não está mais elegante pois não estamos Injetando uma implementação
de uma Interface, mas este é um assunto para outro post!
É isso pessoal, apenas uma pequena dica simples em um artigo simples para deixarmos o nosso código o mais próximo possível do que deve ser: Profissional!
Abraços pessoal!