Skip navigation

   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:

    Vamos começar a “discecar” a solução. Veja que tenho uma classe registry, que será chamada por qualquer camada, haja vista, o registry também poder ser utilizado como um service locator e desta maneira poder ser acessado por qualquer camada da aplicação. Ele faz uso de um container, que é quem armazena os objetos que implementam as abstrações, o registry irá solicitar o container que resolva uma determinada abstração( inteface ou classe abstrata ); note que estamos aqui utilizando a inversão de controle, o registry não faz referencia a uma implementação, e sim a uma abstração de um contaner. Exitem vários containers no mercado, structured map, castle windsor, unity da microsoft enfim uma infinidade de containeres de ibnjeção de dependência. O fato de apontarmos para uma abstração faz com que, independende do container, o que importa e existir alguém, a quem o registry possa pedir para resolver a abstração. Temos ainda uma classe para nos auxiliar a obter as abstrações e suas repectivas abstrações.
 
O Registry
     Veremos o código do registry abaixo:

 
    Note que o container aponta para uma abstração de um container, ou seja, não importa quem ele é o importante é ele ser capaz de resolver a dependência/abstração. Dentro do construtor, é instânciada uma implementação da interface IDIContainer que utiliza o Unity da microsoft para container de injeção de dependência. É responsabilidade do container, armazenar as abstrações( interfaces/classes abstratas) para que possam ser recuperadas quando necessário.
 
IDIContainer
 

     Como dito anteriormente, a função do container é simplesmente armazenar as abstrações e suas respectivas implementações,  Veja o código abaixo:

  Veja que o contrato é simples, um método para registrar a abstração, a alguma classe que a implemente, e um método para recuperar alguma classe que resolva, ou seja, implemente uma determinada abstração.
 
Implementando o IDIContainer

     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.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.