Boas Práticas - O padrão inversão de controle (IoC)


Adotar boas práticas no processo de desenvolvimento de software deixou de ser um diferencial para ser uma questão de sobrevivência.

O cenário atual aponta para uma grande demanda por software de qualidade com prazo e custos cada vez mais reduzidos. Não há mais lugar para desculpas como falta de recursos ou de tempo. Ou você oferece o que o mercado deseja ou esta fora.

Usar padrões é uma das atitudes que beneficia o projeto pois facilita o reuso, os testes e permite uma melhor manutenabilidade do produto.

Este artigo apresenta o padrão inversão de controle (IoC) também conhecido como injeção de dependência (há uma certa polêmica quanto essa correspondência...)

Se você nunca ouviu falar em inversão de controle (IoC) saiba que este padrão é muito usado em projetos orientados a objeto e utiliza conceitos como interface, herança e polimorfismo, e, tem como objetivo reduzir o acoplamento , facilitar o reuso e os testes no projeto de software.

Neste artigo vou dar um enfoque prático ao assunto e procurar mostrar como usar a inversão de controle (IoC) no seu projeto de software .NET. Vamos lá...

Antes de iniciar creio que seria bom lembrar algumas definições importantes que serão usadas neste artigo:

Nota: Veja detalhes sobre o assunto no meu artigo : http://www.macoratti.net/vbn_oopc.htm

1- Objeto

- Um objeto é a representação de um modelo abstrato definido em uma classe;
- Um objeto é uma instância de uma classe;
- O estado de um objeto é o conjunto de suas propriedades;
- Cada objeto tem o seu próprio estado;
- O comportamento de um objeto são as funções (métodos) que afetam suas propriedades e/ou as propriedades de outros objetos;

2- Classe

- Uma classe é o modelo a partir do qual os objetos serão criados;
- Um objeto é uma instância de uma classe;
- Uma classe define as propriedades e comportamento que cada uma de suas instâncias(objetos) possuirá;
- Classes podem se comunicar em entre si trocando informações(dados, parâmetros, controles,etc.);

3- Acoplamento

- Acoplamento é o nível de dependência/conhecimento que pode existir entre as classes;
- Uma classe com acoplamento fraco não é dependente de muitas classes para fazer o que ele tem que fazer;
- Uma classe com acoplamento forte depende de muitas outras classes para fazer o seu serviço;
- Uma classe com acoplamento forte é mais difícil de manter, de entender e de ser reusada;


4- Coesão

- Coesão é o nível de integralidade interna de uma classe; (Veja o principio da responsabilidade única - SRP)
- A coesão Mede o grau que um classe ou seus métodos fazem sentido, ou seja, quão claro é o entendimento do que a classe ou método possui
- Uma classe com alta coesão possui responsabilidades bem definidas e são difíceis de serem desmembradas em outras classes;
- Uma classe com baixa coesão possui muitas responsabilidades, geralmente que pertencem a outras classes, e podem ser facilmente desmembradas em outras classes;
- Uma classe com baixa coesão é difícil de entender, manter e reusar;

Portanto quanto mais forte o acoplamento e mais baixa a coesão de uma classe mais difícil ela será de entender, manter e ser reusada.

Agora vamos a parte prática onde irei mostrar como podemos aplicar o padrão inversão de controle.

Nota: Todos os códigos mostrados foram obtidos usando o Visual Basic 2005 Expres Edition

Abaixo temos o código da classe A (A.vb) que usa uma outra classe B (B.vb):

Public Class A

    Private b As B
                                             
    Public Sub New()
        b = New B()
         Console.WriteLine("Foi criado o objeto b")
    End Sub

End Class
A classe A acessa diretamente a classe B criando uma instância da classe no seu construtor.

Vamos supor que :

  • A classe B é uma classe concreta com um construtor padrão;

O código da classe B é dado a seguir:

Public Class B

    Public Sub New()
        Console.WriteLine("Foi criada uma instância da classe B")
    End Sub
End Class

Neste exemplo temos um forte acoplamento entre a classe A e a classe B pois quem controla a criação de uma instância da classe B é a classe A.

A classe A é responsável por obter uma referência a classe B.

Qualquer alteração que ocorra na classe B vai afetar diretamente a classe A pois esta possui uma referência a classe B.

Como fazer com que a classe A não seja afetada pelas mudanças feitas na classe B sem perder a referência para a classe B ?

Como diminuir o acoplamento entre a classe A e a classe B ?

Podemos fazer isso usando o padrão inversão de controle (IoC).

Nota: Existem diversos frameworks que usam o padrão IoC e que efetuam a injeção de dependência.

Vemos abaixo a classe A(A.vb) ajustada para usar o padrão IoC:

Public Class A
   Private b As B

   Public Sub New()
   End Sub

   Public Sub setB(ByVal b As B)  
       Me.b = b
   End Sub
End Class


Agora a classe A obtém uma referência da classe B usando o método setB();

- Dessa forma a classe A pode obter uma referência da classe B sem saber como a classe B é instanciada
- A classe B pode ser uma interface, classe abstrata ou mesmo uma classe concreta.

- Não existe mais nenhum acoplamento entre a classe A e a classe B;

- Qualquer alteração feita na classe B não afeta a classe A e vice-versa;

 

Se houver uma alteração no método da classe B a classe A deverá ser alterada também mas a criação do objeto b não tem a sua implementação na classe A, podemos usar o método setB() para injetar o objeto b.

Perceba que todos os conceitos aqui abordados usam princípios básicos da programação orientada a objetos e que não existe segredo algum, então quando se ouve falar que "O framework XYZ usa a injeção de dependência..." ,  ele esta basicamente usando os recursos que expomos neste artigo e que são os pilares da programação orientada a objetos:

Obs: O “Unity Application Block" do “Enterprise Library 4.0” é um container de inversão de controle baseado na biblioteca “ObjectBuilder2” do “Entreprise Library” e que foi lançado como uma alternativa às já tradicionais bibliotecas “Spring.NET” (uma versão da famosa biblioteca Spring do mundo Java), “Castle Windsor”, “StructureMap”, “ObjectBuilder” etc.

referências:


José Carlos Macoratti