As várias formas de fazer inversão de controle



Como eu já descrevi em um artigo anterior, a inversão de controle é um padrão de projeto (também chamado Design Pattern) que prega remover de uma classe o controle (ou responsabilidade) de instanciar outras classes e passar esse controle (responsabilidade) para um componente externo do sistema, sendo ele um framework, um container, uma classe, um serviço e etc.

Inversão de controle por injeção de dependência

A forma mais comum de fazermos a inversão de controle é por meio da injeção de dependência que é também outro desiign pattern 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? Ao injetarmos em uma classe as dependências que ela vai utilizar (injeção de dependência) por consequência, retiramos dessa mesma classe o controle de instanciar suas classes dependentes (inversão de controle). Como dito antes a injeção de dependência é uma forma de se realizar a inversão de controle.

Exemplo:

Uma classe para processar vendas de carros em uma loja de carros:

public class VendaDeCarro {

 

            private Carro carro = new Carro();

 

            private MySQL mysql = new MySQL();

 

 

            public void vendeCarro() {

 

                //Todo o código para a venda do produto...

 

                mysql.grava(Carro);

 

            } 

} 

Veja que nesse exemplo a VendaDeCarro utiliza as classes MySQL e Carros para registrar os carros vendidos em um banco MySQL, mas e se a empresa quiser utilizar outro banco de dados para gravar seus dados, ou passar a vender outro produto além de somente carros? Nesse caso teríamos que reescrever a classe VendaDeCarro ou criar uma classe para cada novo tipo de produto vendido.

Mas poderíamos resolver isso facilmente utilizando a injeção de dependência para criar um código desacoplado e flexível a mudanças.

public interace Banco { 

}

 

public interface Produto {


}

  

public class VendaDeProduto {

 

            private Produto produto;

 

            private Banco banco;

 

 

 

            public VendaDeProduto(Produto produto, Banco banco) {

 

                        this.produto = produto;

 

                        this.banco = banco;

 

            }

 

  

            public void vendeProduto() {

 

                //Todo o código para a venda do produto...

 

                banco.grava(produto);

 

            }

} 

Nesse exemplo a classe VendaDeProduto pode lidar com qualquer classe que implemente as interfaces Produto e Banco, sejam elas classes que abstraíam produtos como carros, peças, acessórios ou classes que trabalhem com diferentes bancos de dados com MySQL, Oracle ou etc.

Veja:

VendaDeProduto vendadepeca = new VendaDeProduto(Peca, Oracle);

 

VendaDeProduto vendadepeca = new VendaDeProduto(Carro, MySQL);

 

Nesse exemplo a classe VendaDeProduto vai registrar a venda de uma peça em um banco Oracle e futuramente a venda de um carro em um banco MySQL.

Mas também é possível fazer inversão de controle sem injeção de dependência. isso mesmo! É possível fazer inversão de controle por meio de programação funcional e também por orientação a eventos críticos.

Inversão de controle por meio de programação funcional

Analise o código a seguir:


public interface Calculo {

 

public int calcular(int valor);  

      

}

 

public class Main {

 

       public static void main(String[] args) {

      

            

       System.out.println("Criação e teste de funçoes lambda");   

      

       // Injetei o comportamento de dobrar o valor recebido e imprmí-lo na tela.

       Calculo calculo1 = (v) -> {return v*v;};

      

       System.out.println(calculo1.calcular(10));

      

       calculo1 = (v) -> {return v+v;};

      

       System.out.println(calculo1.calcular(10));

      

       }

 

}

 

Nesse código primeiramente criamos uma interface chamada Calculo, essa interface é um tipo de interface chamada interface funcional.

O que são Interfaces Funcionais?

Interfaces Funcionais são todas as interfaces que possuem um único método à ser implementados, ou em outras palavras, um método abstrato. No nosso código, por exemplo, a interface Calculo possuí um único método que se chama calcular. O compilador consegue reconhecer essas interfaces e disponibilizá-las para o desenvolvedor trabalhar, por exemplo, com funções Lambdas.

O que são funções Lambdas?

Uma função lambda é uma função sem declaração, isto é, não é necessário colocar um nome, um tipo de retorno e o modificador de acesso. A ideia é que o método seja declarado no mesmo lugar em que será usado. As funções lambda em Java tem a sintaxe definida como (argumento) -> (corpo), como mostram o nosso código:


Calculo calculo1 = (v) -> {return v*v;};

 

calculo1 = (v) -> {return v+v;};

 

Nesses códigos também podemos ver exemplos de inversão de controle pois injetamos o comportamento que queríamos para a função calcular, dessa forma a função Main ficou sem o controle de instanciar as implementações de Calculo que são utilizadas ao longo do código.

Neste artigo vou me restringir a mostrar apenas como fazer inversão de controle por Injeção de dependência e por programação funcional para manter a simplicidade e fácil entendimento do artigo.

Até a próxima :)

 

Comentários

Postagens mais visitadas deste blog

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

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

Como instalar a linguagem SOL no Windows