Artigo do tipo Tutorial
Recursos especiais neste artigo:
Contém nota Quickupdate, Conteúdo sobre boas práticas.
Spring.NET - Como utilizar Injeção de Dependências (DI) e Inversão de Controle (IoC) em Aplicações Multicamadas
A Injeção de Dependências veio para trazer mais desacoplamento à programação, apesar da técnica não ser nova, com o advento das grandes aplicações e da necessidade de maior reuso e testabilidade, este assunto voltou com força total e tem sido conversa frequente entre arquitetos e engenheiros. Veremos todos os conceitos à cerca de DI e IoC juntos com o Spring.NET e depois vamos criar uma aplicação desde a UML até a implementação final da camada de apresentação, aplicando assim o Spring e sua injeção de dependências em um cenário bem próximo do real.


Em que situação o tema é útil

Este artigo é útil a qualquer aplicação .NET onde se deseje ter um maior nível de desacoplamento e testabilidade, aumentando ainda o reuso e consequentemente a produtividade das equipes que empregarem as práticas citadas aqui.

O termo Injeção de Dependências foi usado pela primeira vez por Martin Fowler em seu famoso artigo chamado Inversion of Control Containers and the Dependency Injection pattern que em português significa Containers de Inversão de Controles e o Padrão de Injeção de Dependências.

Quando ouvimos falar de “fraco acoplamento” devemos compreender que os objetos precisam ter apenas dependências necessárias para desempenharem bem o seu papel e estas dependências precisam ser muito poucas. Estas dependências de objetos devem ser uma interface e não uma classe concreta. Esta é a vantagem de se usar o fraco acoplamento, porque oferece usabilidade, manutenibilidade e principalmente testabilidade para as aplicações.

De acordo com Fowler, os termos Injeção de Dependências (DI) e Inversão de Controle (IoC) são muito parecidos: tendo a DI alguns tipos a menos que IoC, de forma que se use apenas o que há de melhor na IoC. O motivo da troca de nome fora apenas de semântica para que possa facilitar a compreensão do leitor e daqueles que estão aprendendo este padrão de desenvolvimento.

O objetivo da Injeção de Dependência é separar objetos que populam outros – tais objetos são chamados de montadores, ou assemblers – dos que fazem uso de implementação de interfaces, onde esta implementação é chamada de serviço.

A Injeção de Dependências consiste em dois tipos ou estilos principais:

1) Injeção via Construtor

2) Injeção via Setter

Injeção via Construtor

Consiste em passar um objeto de Serviço que será injetado diretamente na classe via construtor. Na Listagem 1 podemos ver um exemplo de uma interface com os métodos de operação no banco de dados, enquanto que na Listagem 2 temos a simulação de uma classe concreta implementando esta interface. Observe que na linha 5 temos a variável de instância que será injetada na classe e na linha 13 temos a injeção propriamente dita através do construtor da Classe.

Listagem 1. Interface


  01    public interface IContatoDAL
  02     {
  03       void Salvar(Contato entidade);
  04       List<Contato> listarTudo();
  05       Contato listarPorId (int id);
  06       void Atualizar(Contato entidade);
  07       void Apagar(Contato entidade);
  08     }

Listagem 2. Classe acessando o Serviço IContatoDAL


  01 public class ContatoDAL:IContatoDAL    
  02    {  
  03       #region Atributos
  04       public Conexao Conexao{ get; set; }
  05       #endregion
  06       #region Construtor
  07       public ContatoDAL(Conexao conexao)
  08       {
  09         this.Conexao = conexao;
  10       }
  11       #endregion
  12     }

Injeção via setter

Faz a DI em um método set dentro da Classe que irá acessar o serviço, bastando referenciá-lo no framework para injetá-lo na Classe que irá consumir o serviço, como mostra a Listagem 3.

Listagem 3. Injeção de Dependências via Setter


   
         01  public class ManterContato : IManterContato
         02  {                  
         03   //pode ser feito desta forma
         04   private IContatoDAL dao;
         05   
         06   public IContatoDAL Dao
         07   {
         08         set { dao = value; }
         09   }              
         10   
         11   //ou pode ser feito desta forma
         12   
         13   public IContatoDAL Dao {get; set;}
         14   
         15   //Implementação da Classe
         16  }

Veja na Listagem 3 que a dependência que a classe ManterContato têm da interface IContatoDAL é passada através de um método Set, dessa forma não precisamos inicializar a variável (linha 4), visto que o container de IoC/DI fará isso automaticamente assim que a classe ManterContato for utilizada na aplicação. Além disso, podemos observar nesta mesma listagem que podemos fazer isso através de uma propery manual (linha 6) ou através de uma property automática (linha 13).

Spring.NET

O Spring.NET é uma versão .NET do framework Spring criado para java e que é largamente usado pela comunidade do mesmo, sendo que o Spring.NET não se limita à injeção de dependências, que é o seu propósito básico, mas estende suas funcionalidade à integrações em aplicações corporativas.

O Spring.NET contém módulos de integração para frameworks como NHibernate para persistência, AOP – Programação Orientada a Aspectos, ASP.NET MVC 2, ASP.NET MVC 3, NUnit para testes, Integração SOA e MQs para troca de mensagens entre aplicações utilizando barramentos, conforme podemos ver na Figura 1.

O Spring.NET é uma solução de Container de IoC/DI para .NET, fazendo frente aos já estabelecidos frameworks Ninject , Structure Map, Castle Windsor e Unity, contendo uma semântica idêntica a do java, porém com implementações totalmente distintas, até por serem linguagens diferentes.

Figura 1. Módulos do Spring.NET

Devido à extensão do assunto, neste artigo utilizaremos apenas o módulo Core do framework pelo fato de que o mesmo é a base para compreensão geral do Spring.NET.

Para instruções detalhadas sobre o que faz cada módulo, consulte a seção links. Porém, entendendo a Spring.Core podemos compreender melhor os outros módulos.

Por que usar o Spring.NET?

Para responder a esta pergunta, vamos observar uma implementação sem o Spring e outra com o Spring.

Para fins de exemplo, vamos criar uma classe chamada Conexão que fará uma simulação de acesso ao Banco de Dados, para isso criaremos ainda uma interface chamada IClasseDAL para o serviço da ClasseDAL. Na Listagem 4 podemos ver estas classes, onde temos a classe de conexão (linha 1 à 9), a interface IClassDAL (linha 10 à 15), ClasseDAL (linha 17 à 47) e Principal (linha 49 à 60), que seria para simulação da execução da aplicação.

Neste caso, na ClasseDAL temos dois construtores implementados. No primeiro, sem parâmetros, teríamos que instanciar uma nova conexão para ser utilizada pelos métodos da classe. Já no segundo receberíamos a conexão via parâmetro. Além disso, nos métodos da classe temos que Abrir (linha 31) e Fechar (linha 43) a conexão para controlar a memória e evitar problemas de performance.

Listagem 4. Implementação sem Spring.NET


  01     public class Conexao {
  02      public Boolean IsConectado {get; set;}
  03       public String Conexao {get; set;}
  04       public Conexao(){
  05             this.conexao = "Data Source=ALLSPARK;Initial 
                Catalog=ANS;User ID=usuario";
  06             
  07             //instruções de conexão
  08       }
  09     }
  10     public interface IClasseDAL{
  11     
  12       List<Object> listarTudo();
  13       void Salvar(Object o);
  14       void Excluir(Object o);
  15     }
  16     
  17     public class ClasseDAL : IClasseDAL {
  18       private Conexao conexao = null;    
  19       public ClasseDAL(){
  20             this.conexao = new Conexao();
  21       }
  22       
  23       public ClasseDAL(Conexao conexao){
  24             this.conexao = conexao;
  25       }
  26       
  27       private List<Object> listarTudo(){
  28             
  29             try{
  30                   
  31                   conexao.abre
  32                   //Operação
  33                   //...
  34                   ...
  35                   ...
  36                   ...
  37             } catch {
  38             
  39                   throw;
  40             
  41             } finally {
  42                   
  43                   conexao.fecha
  44             
  45             }
  46       }     
  47     }
  48     
  49     public class Principal {
  50       
  51       public static void main(){
  52       
  53             Object classe = new Object();
  54             
  55             ClasseDAL dal = new ClasseDAL();
  56            
  57             dal.Salvar(classe);
  58       }
  59       
  60     }

Na linha 55 instanciamos ClasseDAL para permitir que o objeto DAL acesse todas as operações necessárias. Observe que neste caso utilizamos o construtor padrão da mesma, desta forma a conexão foi criada dentro da própria classe.

Na Listagem 5 temos as mesmas classes existentes na Listagem 4, porém, com o uso do Spring.

Listagem 5. Mesma implementação utilizando o Spring


   
  01     public class ClasseDAL : IClasseDAL {
           
  02       private Conexao conexao;
           
  03       public Conexao PConexao {
           
  04             set {
  05                   conexao = value;
  06             }
           
  07     }
                 
  08       private List<Object> listarTudo(){
                 
  09             try{
                       
  10                   conexao.Commit;
  11                   //Operação
  12                   //...
                       ...
                       ...
                       ...
  13             } catch {
                 
  14                   conexao.Rollback;
                 
  15             }
  16       }     
  17     }
         
  18     public class Principal {
         
  19       public static void Main(){
                 
  20             IApplicationContext di = ContextRegistry.GetContext();
  21             IClasseDAL dal = (ClasseDAL) di.GetObject("ClasseDAL");
                 
  22             dal.listarTudo();
                 
  23       }
  24     }

Veja que neste caso estamos utilizando a injeção via setter, através da propriedade da linha 5. Além disso, na linha 36 temos a criação da ClasseDAL através do método GeoObject do Spring.

Após sua implementação, precisamos registrar os objetos para que o Spring.NET possa reconhecê-los, existindo duas formas para isso:

1) Registrar o mesmo dentro do arquivo App.Config ou Web.Config propriamente marcado com as tags do Spring. Esta é a forma que será utilizada neste artigo, devido á simplicidade do mesmo.

2) Usar um arquivo .xml separado fazendo uma menção a eles nos App.Config\Web.Config fazendo com que o Spring aponte para este arquivo. Esta é a melhor opção caso o seu sistema seja grande e com muitas regras de negócios e implementações que necessitem de Injeção de Dependências, esta é uma forma de deixar mais organizado e facilitar a manutenção do seu código.

...

Quer ler esse conteúdo completo? Tenha acesso completo