Injeção de Dependências com Microsoft Unity e DDD

Neste artigo veremos como utilizar o padrão de Injeção de Dependências em projetos ASP.NET MVC seguindo a metodologias Domain-Driven Design.

Fique por dentro
Neste artigo o leitor aprenderá a aplicar o padrão de Injeção de Dependências em aplicações ASP.NET MVC com a metodologia Domain-Driven Design. Seguindo essas práticas, obtém-se uma arquitetura com baixo acoplamento entre os componentes e alta coesão, uma vez que cada camada tem suas atribuições bem definidas e não depende diretamente das implementações concretas das demais, comunicando-se principalmente através de interfaces.

Ao longo dos anos, na busca por aperfeiçoar e compartilhar conhecimento, conversamos com arquitetos e desenvolvedores em conferências e fóruns sobre como esses resolvem alguns problemas comuns durante o desenvolvimento de software, principalmente aqueles relacionados à arquitetura das aplicações. O que constatamos é que a maioria faz uso de padrões já conhecidos, em geral adaptando-os às suas necessidades. Em sistemas de grande porte, onde há várias camadas e componentes compondo uma arquitetura complexa, essas soluções visam principalmente auxiliar no controle das dependências no projeto, ou seja, dependências entre objetos, entre comandos e ações, entre eventos e entre artefatos de todos os tipos.

Para a maior parte dos problemas arquiteturais que conhecemos, existe um conjunto de padrões de desenvolvimento que fornecem orientações úteis e que ajudam os desenvolvedores a construírem, principalmente, sistemas fracamente acoplados com um mínimo de dependência entre os componentes. Esses padrões auxiliam, entre outros fatores, na criação e uso de objetos que implementam certas responsabilidades, como os padrões Factory, Builder, Lifetime, Inversão de Controle (IoC, do inglês Inversion of Control) e Injeção de Dependências (ou DI - Dependency Injection).

O Microsoft Unity

O Unity é um container para injeção de dependências leve e extensível com suporte a injeções por construtor, propriedade e chamada de métodos. Seu uso facilita a construção de aplicações com fraco acoplamento e garante algumas vantagens ao desenvolvedor, a saber:

· Criação de objetos simplificada, especialmente para estruturas hierárquicas e dependências;

· Abstração de requisitos, que permite aos desenvolvedores informarem as dependências durante a execução ou via configuração, além de gerenciamento simplificado;

· Aumenta a flexibilidade por transferir a configuração dos componentes do ambiente do ciclo de vida para o container;

· Capacidade de localização de serviços, o que permite aos clientes acessarem o container ou seu cache;

Esse container pode ser usado em qualquer aplicação .NET e dispõe de todas as funcionalidades encontradas em mecanismos de injeção de dependência, tais como métodos para registrar e mapear tipos e instâncias, resolver e gerenciar o ciclo de vida de objetos, os injetando via parâmetros em construtores, métodos e valores de propriedades.

No Unity também temos a liberdade para criar extensões que alteram o comportamento do container e adicionam novas funcionalidades. Por exemplo, a funcionalidade de interceptação disponível no Unity, que podemos utilizar para capturar chamadas de objetos e adicionar funcionalidades e políticas para os objetos alvo, é uma implementação de uma extensão do container.

Tipos de Injeção de Dependências utilizados com o Unity

Injeção por construtor

Normalmente, quando instanciamos um objeto, invocamos o construtor da classe com o operador new e passamos qualquer valor que o objeto precisa como parâmetro. Na Listagem 1 a classe ContatoDao espera receber em seu construtor um objeto que implemente a interface ISessionFactory. Esse é um exemplo de injeção via construtor e é o tipo mais utilizado. Observe que a classe não depende de uma implementação concreta para ser instanciada, ela agora necessita apenas que um certo contrato (interface) seja seguido para que o parâmetro seja compatível com o esperado no construtor. Esse será o tipo utilizado neste artigo.

Listagem 1. Exemplo de Injeção via Construtor

01 public class ContatoDao: DaoAbstratoGenerico<Contato>, IContatoDao 02 { 03 public ContatoDao(ISessionFactory sessionFactory) 04 :base(sessionFactory) 05 { 06 07 } 08 } 09 public void InjecaoViaConstrutor() 10 { 11 container.RegisterType<ObjetosDeApoio.IContatoDao, ObjetosDeApoio.ContatoDao>( 12 new InjectionConstructor(HibernateUtil.FabricaDeSessao) 13 ); 14 15 ObjetosDeApoio.IContatoDao dao = container.Resolve<ObjetosDeApoio.IContatoDao>(); 16 17 Assert.IsTrue(dao.BuscarTodos().Count > 0); 18 }

Nas linhas 11 a 13 dessa listagem estamos utilizando o módulo de injeção via construtor do Unity, informando que os objetos do tipo IContatoDao serão instanciados como ContatoDao (classe concreta que implementa essa interface) e para eles deverá ser passado o objeto HibernateUtil.FabricaDeSessao, que implementa a interface ISessionFactory esperada como parâmetro na linha 3. Em seguida, na linha 15 testamos o mecanismo que configuramos, criando um objeto do tipo IContatoDao a partir do método Resolve do container, que irá criar retornar um objeto do tipo ContatoDao com a fábrica de sessão já instanciada. Na linha 17 apenas verificamos se o objeto foi instanciado corretamente, avaliando se ele realmente consegue acessar a base de dados e retornar os registros esperados.

Injeção via propriedade

O Unity, como outros containers robustos do mercado, também trabalha com a possibilidade de injeção via propriedade. Mesmo que o recomendado seja trabalhar com a injeção via construtor, podem ocorrer situações onde só há a possibilidade de utilizar este segundo tipo, que em outros containers também é chamado de injeção via setter.

Existem casos em que a injeção via propriedade é recomendada:

· Quando precisamos instanciar objetos dependentes automaticamente quando instanciamos o objeto pai;

· Quando queremos uma forma simples, que torna fácil a leitura do código, para encontrar as dependências de cada classe envolvida;

· Quando o objeto pai precisa de um grande número de construtores que acessam vários objetos e tornam a manutenção e a depuração mais difíceis;

· Quando o construtor da classe base necessita de um grande número de parâmetros, especialmente se eles são de tipos parecidos e existe apenas um modo de identificá-los por sua posição;"

[...] continue lendo...

Artigos relacionados