Por que eu devo ler este artigo:Existem cenários comumente encontrados onde o desenvolvedor precisa criar aplicativos flexíveis e acopláveis a diferentes regras de negócio, havendo casos inclusive onde a aplicação deve se portar de forma diferente dependendo do cliente, mas sem que seja necessária uma nova compilação completa do sistema. A Inversão de Controle ajuda nesses casos, pois permite o desenvolvimento de aplicativos que podem ser facilmente acoplados a vários tipos de cenários, alterando e atualizando apenas os pontos específicos que requerem modificação.

É de conhecimento (ou deveria ser) de todo desenvolvedor a importância de construir aplicativos da forma mais flexível possível, pois sempre existirá a chance (e provavelmente acontecerá) do software que está sendo construído ter de se adaptar a diferentes cenários.

Imagine que uma empresa construa uma aplicação, inicialmente distribuída para um pequeno grupo de clientes, onde todas as regras estão fortemente acopladas no código da aplicação. O que aconteceria se em determinado momento surgisse à necessidade dessa aplicação ser vendida para outras companhias, cada uma com regras de negócio específicas para uma mesma situação? Por exemplo, em uma aplicação de automação comercial onde a referência dos produtos é gerada automaticamente pelo sistema, mas cada cliente possui uma regra diferente para a criação dessas referências (sequências numéricas, alfanuméricas, com datas, etc.).

Neste artigo será explicado o conceito de Inversão de Controle (do inglês Inverfion of Control, comumente referenciado pela sigla IoC) e problemas que podem ser resolvidos com a utilização deste princípio. Utilizaremos o Visual Studio como ferramenta base e projetos Class Library e Web para ilustrar os exemplos. Também fará parte do artigo a exemplificação de dois Containers (frameworks) de Inversão de Controle: o Unity e o Autofac, que automatizam parte do processo e tornam mais simples o uso de IoC em projetos maiores.

Forte acoplamento

É muito comum encontrarmos forte acoplamento entre componentes ou classes dentro de uma solução. Este termo se refere a situações onde um objeto depende de outro bem específico para existir. O forte acoplamento em softwares faz com que a manutenção se torne bastante complicada, pois geralmente a alteração de um elemento gera a necessidade de alteração em outros, devido a dependência entre eles. Observe um exemplo de forte acoplamento entre classes na Listagem 1.

Listagem 1. Exemplo de forte acoplamento

  01   public class Cliente
  02   {
  03        private Endereco _endereco;
  04
  05        public Cliente()
  06        {
  07            _endereco = new Endereco();
  08        }
  09   }

A classe Cliente possui um vínculo direto com a classe Endereco, ou seja, elas estão fortemente acopladas. Imagine agora que as suas instâncias de Cliente precisem de um novo tipo de Endereco, por exemplo, EnderecoResidencial ou EnderecoComercial, neste caso você teria que alterar as linhas 03 e 07 para utilizar a sua nova classe. Se existissem várias classes que fazem menção direta à classe Endereco, seria necessário alterar uma a uma para obter o resultado esperado. Esse tipo de manutenção demanda tempo e há sempre o risco de deixar algum ponto para trás.

Quanto mais dividido e desacoplado o software, maior é a chance de sucesso tanto na entrega, quanto nas futuras manutenções, pois as alterações geralmente ficam centralizadas apenas nos pontos exatos que requerem modificações.

Existem dois princípios básicos da Inversão de Controle:

· Classes principais que agregam (BOX 1) outras classes não devem depender da implementação direta das classes agregadas. Ambas as classes devem depender de abstração, utilizando interfaces ou classes abstratas.

· Abstrações não devem depender de detalhes. Detalhes devem depender de abstrações. Para explicar melhor esta afirmação, considere o exemplo de um carro. Os pedais e o volante podem ser vistos como abstrações do motor, ou seja, são as funcionalidades expostas por ele para o seu controle. Se um dia alguém quiser trocar o motor do carro para uma versão mais nova, essa alteração será transparente para o motorista,. que continuará usando os pedais e o volante sem ter ciência de que o motor foi trocado. O modo de direção continua o mesmo. Por outro lado, sem os pedais e o volante o motor não tem serventia, demonstrando a dependência do motor das funcionalidades expostas.

BOX 1. Classes agregadas

Quando uma classe possui uma referência direta de outra classe em suas propriedades, dizemos que a segunda está agregada à primeira, ou que a primeira possui uma agregação. Olhando para o exemplo das classes Cliente e Endereco, podemos afirmar que Cliente possui um Endereco e, desta forma, a classe Endereco está agregada à classe Cliente.

Formas de se implementar Inversão de Controle

Inversão de Controle é implementada utilizando um outro princípio chamado Injeção de Dependência. A Figura 1 ilustra o funcionamento desse padrão e a interação entre os princípios.

Figura 1. Inversão de Controle e Injeção de Dependência

A Figura 1 mostra a relação entre a Inversão de Controle e a Injeção de Dependência. A Inversão de Controle é implementada através da Injeção de Dependência, segundo a qual as dependências de um objeto não devem ser definidas diretamente dentro dele no momento de sua criação, mas devem ser inseridas (injetadas) dinamicamente, de acordo com alguma configuração mutável. No exemplo dado, a dependência que a classe Cliente tem da classe Endereço deveria ser removida, sendo definida apenas em tempo de execução. Podemos dizer então que Inversão de Controle (IoC) é um princípio, enquanto a Injeção de Dependência é um meio de implementá-la.

Há quatro formas de implementar a Inversão de Controle, e para entendê-las vamos usar o exemplo do Cliente e Endereco.

Via Construtor

Nesta forma, a referência da classe é passada diretamente via construtor. Então, para criar um Cliente, obrigatoriamente deveria ser passado um objeto que implementa a interface IEndereco, como é mostrado na Listagem 2.

Listagem 2. Exemplo de Injeção de Dependência (DI) via Construtor

  01 public class Cliente
  02 {
  03    private IEndereco _endereco;
  04
  05    public Cliente(IEndereco endereco)
  06    {
  07        _endereco = endereco;
  08    }
  09 }

A utilização de uma interface aqui é importante para manter o baixo acoplamento entre os objetos. Ou seja, a classe Cliente não sabe o tipo de endereço que será passado, ela só sabe que o objeto implementa a interface IEndereco.

Por propriedades

Esta é a forma mais utilizada de Injeção de Dependência. A dependência é exposta através de métodos ...

Quer ler esse conteúdo completo? Seja um assinante e descubra as vantagens.
  • 473 Cursos
  • 10K Artigos
  • 100 DevCasts
  • 30 Projetos
  • 80 Guias
Tenha acesso completo