Inversão de controle x injeção de dependência x inversão de dependência

 



Entenda a diferença entre inversão de controle, injeção de dependência e inversão de dependência.

Nesse artigo vou explicar a diferença entre três conceitos muito usados no mundo da programação: a inversão de controle, a injeção de dependência e a inversão de dependência. Notou como esses três nomes são parecidos? Pois bem, apesar de parecidos esses nomes significam elementos distintos no mundo do desenvolvimento de sistemas,  muitas pessoas confundem esses conceitos, outras sequer sabem da existência de todos os três e existem aquelas ainda que pensam que esses conceitos são sinônimos. O objetivo desse artigo e explicar de forma clara o que são cada um desses conceitos e como eles se relacionam entre si.

Primeiramente entenda:

Inversão de controle é um princípio de design.

Injeção de dependência é um padrão de projetos.

Inversão de dependência é um dos cinco princípios da programação orientada a objetos (SOLID).

Vamos nos aprofundar em cada conceito:

1. Inversão de controle

A inversão de controle é um padrão de projeto que prega remover de uma classe a responsabilidade de instanciar outras classes e passar essa responsabilidade para um componente externo do sistema, sendo ele um framework, um container, uma classe, um serviço e etc. 

Exemplo:


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);
	}
}

Imaginamos que tenhamos que mudar o construtor da classe Log para além de receber o nome do arquivo também tenha que receber o endereço do diretório que o arquivo se encontra, nesse caso, basta fazer a alteração na classe VendaDeProduto, mas e se tivermos  umas trinta classes utilizando a classe Log? Teríamos  que alterar todas as trinta, o que seria um esforço gigantesco.

Para resolver esse problema é que utilizamos a inversão de controle, onde a classe VendaDeProduto não vai mais instanciar a classe Log e sim outro componente do sistema, no caso em questão essa responsabilidade agora é da classe Ecommerce.



public class Ecommerce {
public static void main(String[] args) {
Produto produto = new Produto();
Log log = new Log("Arquivo.txt", "C:\\logs");
VendaDeProduto novavenda = new VendaDeProduto(produto, log)
}
}

Veja que para a implementação acontecer precisamos adicionar um objeto Log no construtor da classe  VendaDeProduto, ao utilizar essa técnica nós entramos no conceito de injeção de dependência que é uma das formas de se fazer a inversão de controle.

2. injeção de dependência

A injeção de dependência é um padrão de projetos que visa utilizar uma estrutura de software  (container)  para "injetar" as dependências usadas por uma classe em vez de deixar com essa classe a responsabilidade de instanciá-las (entenda por dependência  como os atributos e métodos de outras classes ), nessa definição você  notou a correlação com a inversão de controle? Como dito antes a injeção de dependência é uma forma de se realizar a inversão de controle.

Além da forma citada acima existem outras duas formas de se realizar a injeção de dependência, vou descrever cada uma das três:

INJEÇÂO POR CONSTRUTOR

Acontece quando a classe (módulo) a ser utilizada recebe por construtor uma instância de classe que ela mesma irá utilizar (utilização = dependência). No nosso caso, precisamos utilizar o  método construtor  de VendaDeProduto, para isso, a instância de Produto é enviada através do construtor de VendaDeProduto.

O nosso exemplo utilizado para demostrar a inversão de controle é uma injeção de dependência por construtor.



public class VendaDeProduto {
	private Produto produto; 
	private Log log;

	public VendaDeProduto(Produto produto, Log log) {
		this.produto = produto;
		this.log = log;
	}
	
	public void vendeProduto() {
	    //Todo o código para a venda do produto...
	    log.grava(produto);
	}
}


INJEÇÃO POR PROPRIEDADE

Esse tipo de injeção ocorre quando se tem o objeto a ser injetada exposta como um atributo da classe utilizadora.

Classe VendaDeProduto:



Classe VendaDeProduto:
public class VendaDeProduto {
	private Produto produto; 
	private Log log;

	public VendaDeProduto() {
	
	}
	
    	public Produto getProduto() {
		return produto;
	}

	public void setProduto(Produto produto) {
		this.produto = produto;
	}

	public Log getLog() {
		return log;
	}

	public void setLog(Log log) {
		this.log = log;
	}

	public void vendeProduto() {
	    //Todo o código para a venda do produto...
	    log.grava(produto);
	}


}



Classe Ecommerce:



public class Ecommerce {

	
		public static void main(String[] args) {
			Produto produto = new Produto();
			Log log = new Log("Arquivo.txt", "C:\\logs");
			VendaDeProduto novavenda = new VendaDeProduto();
			novavenda.setLog(log);
			novavenda.setProduto(produto);
			}


	}

INJEÇÂO POR INTERFACE

Ao invés de receber o objeto por parâmetro, agora a classe deve receber uma abstração da implementação que ela irá utilizar, através de uma interface. O grande benefício é que quem define qual implementação da abstração será utilizada  é a classe que está chamando a classe dependente.

Classe VendaDeProduto:


public class VendaDeProduto {
	private IProduto iproduto; 
	private ILog ilog;

	public VendaDeProduto(IProduto iproduto, ILog ilog) {
	
	this.iproduto = iproduto;
	this.ilog = ilog;
		
	}
	
	public void vendeProduto() {
	    //Todo o código para a venda do produto...
	    ilog.grava(iproduto);
	}

	
}

Classe Log:



public class Log implements ILog{

	public Log() {
		// TODO Auto-generated constructor stub
	}

	public Log(String string, String string2) {
		// TODO Auto-generated constructor stub
	}

	public void grava(IProduto produto) {
		// TODO Auto-generated method stub
		
	}

}

Classe Produto:



public class Produto implements IProduto {

	public Produto() {
		// TODO Auto-generated constructor stub
	}

}






Exemplo:

Em nosso exemplo, se quisermos deixar de utilizar a classe Log para utilizar uma classe que registre as informações de usuário dentro de uma base de dados basta substituirmos a classe Log, enviada como parâmetro para o construtor de VendaDeProduto, por uma classe que faça a persistência no banco de dados e que também implemente a interface ILog.

Esse exemplo de injeção de dependências por meio de interfaces é o que chamamos de inversão de dependência.

3. INVERSÃO DE DEPENDÊNCIA

Como descrito no início desse artigo a inversão de dependência é um dos cinco princípios da programação orientada a objetos  - SOLID, representada pela letra "D" de  Dependency Inversion Principle (DIP).

A principal definição do princípio da inversão de dependência diz: "Módulos de alto nível não devem depender de módulos de baixo nível e ambos devem depender de abstrações; e abstrações não devem depender de detalhes, mas detalhes devem depender de abstrações.".

Para uma definição mais clara podemos dizer: As classes mais externas de um sistema não devem depender das classes mais fundamentais do sistema e ambas devem depender de interfaces e interfaces não devem depender de detalhes, mas detalhes devem depender de interfaces.

Em nosso exemplo podemos notar que antes de usarmos a inversão de dependência a classe venda de produto dependia diretamente da classe Log para funcionar corretamente como mostra a figura abaixo.



Após a inversão de dependência, a classe VendaDeProduto não depende mais de Log, mas sim de uma interface (abstração) chamada de  ILog, Como Log é uma implementação de ILog, podemos enviá-la sem problemas ao construtor de VendaDeProdutos e se quisermos substituir a classe Log por outra classe basta fazer essa nova classe estender ILog para podermos enviá-la via construtor  para VendaDeProdutos sem problemas.



 

Conclusão

Podemos concluir que a inversão de dependência é uma forma de injeção de dependência e que a injeção de dependência por sua vez é uma forma de inversão de controle.



Espero que esse artigo tenha sido esclarecedor para muitas pessoas em relação ao tema, qualquer dúvida deixe nos comentários ou entre em contato. 

Comentários

Postagens mais visitadas deste blog

Entenda o que são as Razor Pages do .NET CORE

Passo a passo: Criando gráficos com o Google Charts

Como instalar a linguagem SOL no Windows