Bom pessoal hoje, vamos implementar do zero o pattern de arquitetura Registry. O Registry nada mais é do que uma espécie de buscador de objetos, ou seja, um localizador. O Registry sabe onde se encontram os objetos que você precisa, esta é a função dele. Você pode utilizá-lo, quando houver a necessidade de ter um objeto que sabe procurar e achar os objetos que precisam ser localizados e utilizados. O registry também é importante, por que com ele você pode obter inversão de controle, ou seja, você passa a ele o controle e responsabilidade de encontrar os objetos; você apenas solicita a ele e o mesmo retorna o objeto para você. Mais chega de blá, blá blá e vamos meter a mão na massa. Olhe o diagrama abaixo:
Como dito anteriormente, a função do container é simplesmente armazenar as abstrações e suas respectivas implementações, Veja o código abaixo:
A implementação não tem nenhum mistério, precisamos apenas obter as classes e abstrações, referenciados no projeto em que se encontra o container veja o código da implementação para o Unity abaixo:
A implementação consiste apenas em encontrar as classes e abstrações e mapear no container, no caso desta implementação do Unity. Veja no construtor é chamado o método registraClasses, que usa a classe AssemblyHelper para obter todas as abstrações referenciadas no projeto, mapeando para as respectivas implementações. Implementação da interface:
Métodos
Register Type: Registra a abstração para uma implementação.
Resolve: retorna uma implementação de uma determinada abstração.
AssemblyHelper
A classe Assemblyhelper, recupera todas as abstrações e implementações, referenciadas no projeto em que se encontra a implementação do container. É importante para que o registry possa utilizar o container, que você referencie as dll´s em que se encontram as classes e interfaces que você deseja mapear. Código do Assemblyhelper abaixo:
public class AssemblyHelper
{
public IList<Assembly> obterAssemblies()
{
var listAssemblyRetorno = new List<Assembly>();
var objDirInfoRelease = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
var objDirInfoBin = objDirInfoRelease.Parent;
var arquivoDLL = objDirInfoRelease.GetFiles();
foreach (var fileInfo in arquivoDLL)
{
if (fileInfo.FullName.Contains(“.dll”))
{
Assembly objAssembly = Assembly.LoadFrom(fileInfo.FullName);
listAssemblyRetorno.Add(objAssembly);
}
}
return listAssemblyRetorno;
}
public IList<Type> obterClassesPorAssembly(Assembly pAssembly)
{
IList<Type> listaClassesAssembly = new List<Type>();
foreach (var vType in pAssembly.GetTypes())
{
if (vType.IsClass)
{
listaClassesAssembly.Add(vType);
}
}
return listaClassesAssembly;
}
public IList<Type> obterInterfacesPorAssembly(Assembly pAssembly)
{
IList<Type> listaInterfacesAssembly = new List<Type>();
foreach (var vType in pAssembly.GetTypes())
{
if (vType.IsInterface)
{
listaInterfacesAssembly.Add(vType);
}
}
return listaInterfacesAssembly;
}
public IList<Type> obterAbstracoesPorAssembly(Assembly pAssembly)
{
IList<Type> listaInterfacesAssembly = new List<Type>();
foreach (var vType in pAssembly.GetTypes())
{
if (vType.IsInterface)
{
listaInterfacesAssembly.Add(vType);
}
else if (vType.IsClass && vType.IsAbstract)
{
listaInterfacesAssembly.Add(vType);
}
}
return listaInterfacesAssembly;
}
public IList<Type> listaImplementacoesAbstracao(Type pTipoInterface)
{
IList<Type> listaImplInterface = new List<Type>();
foreach (var vAssemblies in this.obterAssemblies())
{
foreach (var vClasse in this.obterClassesPorAssembly(vAssemblies))
{
if (vClasse.GetInterface(pTipoInterface.Name) != null)
listaImplInterface.Add(vClasse);
}
}
return listaImplInterface;
}
public IList<Type> obterAbstracoesNosAssembliesReferenciados()
{
IList<Type> listaAbstracoes = new List<Type>();
foreach (var vAssemblies in this.obterAssemblies())
{
foreach (var vInterface in this.obterAbstracoesPorAssembly(vAssemblies))
{
listaAbstracoes.Add(vInterface);
}
}
return listaAbstracoes;
}
public bool TypeFilter(Type pTipo, object pObjetoFiltro)
{
return pTipo.Name == pObjetoFiltro.GetType().Name;
}
}
Um detalhe importante na implementação deste pattern, é que além de ter um objeto localizador, procurei separar responsabilidades. Se você notar cada classe faz o seu papel, e pede que as outras colaborem quando necessário, é ai que vemos como princípios como o da responsabilidade única, inversão de controle e injeção de dependência tem seu valor; agora se amanhã mudarmos de container e quisermos utilizar o Castle Windsor, por exemplo, basta apenas criar uma classe que implemente a interface IDIContainer e mudar uma linha de código no construtor do registry, exemplo:
public Registry()
{
this.Container = new WindsorDIContainer();
}
Bom pessoal vamos ficando por aqui, espero que vocês tenham gostado do artigo, e me coloco a disposição para quaisquer esclarecimentos. Abraços e até a próxima.

