Desenvolvimento - C#

Inversão de Controle (IoC) e Injeção de Dependência (DI) - Diferenças

Neste artigo iremos explicar de forma simples o uso dos Design Patterns de IoC e DI, suas diferenças e responsabilidades de cada um, utilizando C# como linguagem de Programação.

por Marcos Paulo Lopes Soares



Olá Pessoal! Meu objetivo é explicar de forma simples o uso dos Design Patterns de IoC e DI, suas diferenças e responsabilidades de cada um, utilizando C# como linguagem de Programação.

Existem diversos conteúdos na internet que podem ser facilmente achados, com exemplos dos Patterns e aplicabilidades. Vou apresentar brevemente sobre eles e o meu enfoque será em sua utilização de fato, a relação entre os dois e as vantagens. Então vamos lá.

Inversão de Controle ou Inversion of Control - conhecido pela Sigla IoC é um Pattern que prega para usarmos o controle das instancias de uma determinada classe ser tratada externamente e não dentro da classe em questão, ou seja, Inverter o controle de uma classe delegando para uma outra classe, interface, componente, serviço, etc.

E o que isso quer dizer? Basicamente você não pode fazer isso:

public class Pedido
{
    public void CriarPedido(){
        List<ItemPedido> oItemPedido = new List<ItemPedido>();
    }
}

Dentro da classe Pedido você instanciou diretamente um ItemPedido. Então vamos a situações:

  1. Se der repente o construtor padrão da classe ItemPedido muda? Obrigatoriamente você teria que mudar a classe pedido para adotar esse novo construtor, concorda? Assim violaríamos os conceitos S.O.L.I.D. http://www.slipmp.com.br/blog/index.php/conceitos-s-o-l-i-d/ http://em.wikipedia.org/wiki/SOLID_(object-oriented_design) S = S = Single Responsability / Responsabilidade Única: Uma classe ou método deve ter uma única responsabilidade. Indo além, uma classe deve ter uma e apenas uma razão para mudar. A Sua classe pedido deve mudar porque teve alterações na classe ItemPedido? Então a classe pedido fica com um acoplamento mais alto “pois depende de outras classes” e baixa coesão “pois possui outras responsabilidades que não seja a dela própria”.
  2. Se para criar uma instancia da ItemPedido você precisasse instanciar outro objeto como por exemplo DetalhesDoItem e um dia esse comportamento fosse mudado? Novamente teríamos que mudar a classe Pedido.

É obvio que isso é um exemplo simples e puramente didático. Pense em ambientes corporativos, com sistemas grandes, envolvendo ERP, Várias bases de dados, várias camadas, serviços e afins. Isso com certeza podem causar um impacto grande.

Talvez você gaste mais tempo para desenvolver um sistema totalmente desacoplado, porém você ganha tempo em testes e manutenções.

E como podemos resolver essa situação? Se a classe pedido não pode ter instancias diretas de ItemPedido? Usando a Inversão de Controle!

O Código ficaria assim:

public class Pedido
{
    private ItemPedido _oItemPedido;
    public ItemPedido OitemPedido
    {
        get { return _oItemPedido; }
        set { _oItemPedido = value; }
    }
    public void CriarPedido()
    {
         F (OitemPedido == null)
            throw new Exception(“Não existem Itens para esse Pedido.”);
    }
}

Obs.: Esse exemplo é uma forma de mostrar a Inversão de Controle acontecendo, não se prenda a este exemplo, pois ele é expressado de forma didática.

Agora o trabalho necessário para fazer a classe ItemPedido funcionar, está em outro lugar que não nos interessa a classe Pedido saber. Se ela tem propriedades Chaves, se precisa ter construtor com alguns valores se tem validação, enfim. O que interessa pra classe Pedido é que a ItemPedido está pronta para ser usada.

O ruim dessa abordagem que eu fiz é que a ItemPedido está Pública, qualquer um pode alterar a qualquer hora. Mas não é meu objetivo explicar isso nesse Post. Para isso por favor leia o Post do MVP - Macoratti que explica com detalhes essa visão:

http://www.macoratti.net/11/07/ioc_di1.htm

Pergunta de Programador: “Mas porque você não usou uma Interface? Todos os lugares que eu vejo de exemplos usam interfaces, no seu exemplo você usou a classe concreta”.

A resposta é simples: Isso não faz parte da Inversão de Controle nem da Injeção de Dependência! A Injeção de Dependência apenas injeta a dependência de uma classe para outra classe. A Inversão de controle deixa de ter a dependência internamente da classe e passa para uma classe externa!

Chegamos então a mais um conceito que poucos sabem que é o conceito chamado de Inversão de Dependência. Que é definido pelo o S.O.L.I.D “referência já dada”, que é a letra D:

D = Dependecy Inversion / Inversão de Dependência: Módulos de alto nível não devem depender de módulos de baixo nível, ambos devem depender de abstrações.

Já ouvi muitos programadores falarem apenas de IoC e D.I, mas nunca de Dependecy Inversion. Esse termo é um conceito apenas, para depender de abstrações. E quem aplica ele? A Injeção de Dependência!

Injeção de dependência ou Dependency Injection ou D.I - É um design Pattern que prega um tipo de controle externo "Um container, uma classe, configurações via arquivo, etc." inserir uma dependência em uma outra classe, darei um exemplo simples:

public class Factory
{
    public ItemPedido RetornarItemPedido()
    {
        //Realiza toda a programação necessária para criar a classe ItemPedido.
        Return new ItemPedido();
    }
}
public void CriarPedido()
{
    Factory oFactory=new Factory();
    ItemPedido oItemPedido = oFactory.RetornarItemPedido();

    //... Código para criar o pedido.
}

Existem Frameworks Prontas que já te dá todo um suporte para inserir as dependências de forma dinâmica, utilizando containers e uma série de outras Features, como por exemplo: Unity do Enterprise Library da Microsoft e também o Ninject - projeto open source para Injeção de dependência. Para o Ninject eu recomendo a leitura do Denis Ferrari: http://www.heroisdati.com/ninject-injecao-de-dependencia-simples em relação ao Unity da Microsoft eu criarei um Post sobre ele posteriormente aqui.

Vantagens

  • Deixar seu código desacoplado
  • Facilitar nos testes e isolando seus componentes
  • Aplicável em cenários onde podemos trocar o comportamento do sistema, utilizando classes que realizam as mesmas funcionalidades, porém de fontes diferentes.

Desvantagens

O uso excessivo de IoC e D.I pode acarretar em um tempo muito maior em mão de obra para novas funcionalidades. Você ter seu sistema 100% desacoplado também pode ser ruim, pois talvez você não use toda essa estrutura.

Afinal, usar qualquer Pattern de forma obsessiva é ruim, chamamos isso de Patternite “Quando o programador está tão obcecado por Patterns que usa em todo o seu projeto” chega um momento que para realizar um "Hello World” você constrói 6 camadas, 1 factory, com IoC, D.I, Observer/Listener, Orientado a serviço, com MVVM, etc. Assim o seu sistema não lhe trás vantagens, pelo ao contrário, pode até ficar lento e principalmente de difícil entendimento.

E quando eu devo usar então?

Use quando existe a possibilidade de trocar um comportamento no sistema em determinado componente, ou quando você deseja isolar esses componentes para testes. E lembre-se: Um padrão é aplicado para um problema decorrente em determinados cenários. Se você não tiver essa necessidade, não tem o porquê de aplicar esse padrão.

Tudo isso que eu prego é algo que adquiri com experiência própria desenvolvendo um sistema grande, totalmente desacoplado. Hoje nesse projeto eu consigo ver "e também qualquer outro desenvolvedor da minha equipe" as desvantagens de aplicar isso de forma desnecessária.

Pessoal existe um Post muito bom também que mostra um caso prático que utiliza todos os Patterns abordados aqui nesse artigo lá aplica todos esses padrões, mostrando um cenário prático na qual eu apoio a usar os padrões abordados nesse artigo. Que é mudar o comportamento do sistema, utilizando uma outra ferramenta ORM "Object Relational Mapping" mudando apenas um parâmetro da Factory.

Espero que tenham gostado e que eu tenha alcançado meu objetivo: Desmistificar o uso desses Patterns e facilitar o entendimento desse Pattern, onde em muitos lugares é apresentado de forma muito obscura. É isso ai pessoal. Abraços!

Marcos Paulo Lopes Soares

Marcos Paulo Lopes Soares - Pós-Graduando em Projeto e Desenvolvimento de Sistemas pela Mackenzie e Bacharelado em Sistema de Informação pela FIAP. Sou Analista de Sistemas, com mais de 5 anos de experiência em desenvolvimento de Software .NET e experiência em Java também. Certificado MCP,MCTS e MCPD em ASP.NET 3.5. Site: www.slipmp.com.br Blog: www.slipmp.com.br/blog