Where and when to decide which concrete class (which implements a given interface) should be instantiated?

Asked

Viewed 51 times

1

Okay, this is the classic problem to be solved with the use of interfaces, right? Let’s take the example:

I have a DLL that will be used by different companies, each with their bank and their Pessoa register, I want to provide an interface for different companies to implement their Pessoa DAO’s, example:

Interface that I will provide for each company to implement its DAO

interface IDAOPessoa
{
    Pessoa ObterPessoa(string nome);
}

Empresa1 will probably develop something like this

public class DAOPessoaEmpresa1 : IDAOPessoa
{
    public Pessoa ObterPessoa(string nome)
    {
        // Select * from TBL_PESSOA WHERE nome = @nome
    }
}

Company 2 will probably develop something like this

public class DAOPessoaEmpresa2 : IDAOPessoa
{
    public Pessoa ObterPessoa(string nome)
    {
        // Select * from PESSOA WHERE NM_PESSOA = @nome
    }
}

When each company instance the DLL where these classes are, the company passes a parameter to the DLL to identify which company is using the DLL at that time. So the obvious code to decide which instantiation DAO would be something like this:

public class InicioDLL
{
    public IDAOPessoa daoPessoa { get; set; }
    public InicioDLL(string nomeEmpresa)
    {
        switch (nomeEmpresa)
        {
            case "Empresa1":
                daoPessoa = new DAOPessoaEmpresa1();
                break;
            case "Empresa2":
                daoPessoa = new DAOPessoaEmpresa2();
                break;
        }
    }
}

Of course this code is not sustainable or maintainable because I would have to do it every time I needed an Idaopessoa (or create a factory for it).

Hence the questions come:

  1. Where and how to decide which Concrete Person DAO to instantiate?
  2. Could an DI framework be useful in these cases? If so, you can give an example?
  • 1

    Tip: You need to create two interface for each Dal and do not call directly on this.

  • 2

    Unless I have understood something wrong for me it probably shouldn’t even be solved this way. Should have a class only with the delegated method for each company. Every time someone uses reflection a panda dies. In some cases the switch may be good solution, or else could have a class registration system in a array, in a variation of what is usually done with Observable.

1 answer

3


You can implement a two-part solution: Dynamic assemblies via Reflection, and resolution of instance.


Charge of Assemblies via Reflection

Once compiled the client generated classes can be arbitrarily made available and loaded via Reflection, making them available during Runtime in the Appdomain current.

In the bootstrap of your application Assembly created by the client:

System.Reflection.Assembly
    .LoadFrom("C:\solucao\DefinicoesDeCliente.dll");

Instance resolution

Your application has been initialized correctly, the Assembly client has been loaded, and now you need to instantiate the class that implements IDAOPessoa created by him.

First let’s determine the type to be instantiated:

Type ti = typeof(IDAOPessoa);

Type alvo = null;

foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) {
    foreach (Type t in asm.GetTypes()) {
        if (ti.IsAssignableFrom(t)) {
            alvo = t; // Agora sabemos o tipo utilizado pelo cliente.
        }
    }
}

(Modified version of https://stackoverflow.com/a/26745/1845714)

Possession of the type can now create an instance of the class:

IDAOPessoa instanciaDao = 
    (IDAOPessoa)System.Activator.CreateInstance(alvo);

You can now call methods instanciaDao:

var pessoa = instanciaDao.ObterPessoa("Ewerton");
  • 2

    Look, he lives on!

  • 1

    @Bacchus "Ancient spirits of evil, transform this decadent form into Onosendai-Ra, the one of eternal life!"

Browser other questions tagged

You are not signed in. Login or sign up in order to post.