简体   繁体   中英

dynamically initialize classes implementing a generic interface

I have the following code base:

public abstract class Business
{
    public BusinessType BusinessType { get; set; }
}

public class BusinessA : Business
{
    public string SpecialA { get; set; }
}

public class BusinessB : Business
{
    public string SpecialB { get; set; }
}

A generic interface and classes that are implementing that interface:

public interface IBusinessMapper<T>
{
    void DoMapping(T business);
}

public class BusinessMapperA : IBusinessMapper<BusinessA>
{
    void DoMapping(BusinessA business)
    {
        //...
    }
}

public class BusinessMapperB : IBusinessMapper<BusinessB>
{
    void DoMapping(BusinessB business)
    {
        //...
    }
}

Now I want to create an instance of class BusinessMapperA or BusinessMapperB depending on some value. Is it possible to use something similar to this?:

public class Core
{
    public void Process(Business newBusiness)
    {
        var mapper = GetBusinessMapper(newBusiness.BusinessType);
        mapper.DoMapping();
    }

    private IBusinessMapper<T> GetBusinessMapper(BusinessType businessType)
    {
        switch (businessType)
        {
            case BusinessType.A:
                return new BusinessMapperA();

            case BusinessType.B:
                return new BusinessMapperB();

            default:
                throw new Exception("Not supported");
        }
    }
}

It is not a recommended idea to create an instance of IBusinessMapper<T> depending on a switch case, because it introduces a strong coupling between your abstraction (interfaces) and your implementation.

You could use instead polymorphic dispatch: a Business class may be able to return its own mapper. Something like:

public abstract class Business
{
    public BusinessType BusinessType { get; set; }
    public abstract IBusinessMapper GetMapper():
}

However since your mappers are generic interfaces you cannot return a common type from the method; even your switch case cannot do it. I would rather look into either mapping your types to their mapper in a dictionary or use IoC in order to resolve IBusinessMapper<T> depending on the type of the business object.

So your resolution method would become:

private IBusinessMapper<T> GetBusinessMapper<T>()
{
    // find what class implements IBusinessMapper for the type that's being passed
}

There are many ways to resolve the class you need:

  • Finding classes implementing a specific interface
  • Using a IoC framework
  • Keeping track of the relationship between a Business class and a IBusinessMapper<> manually

EDIT Looking into the idea a bit more, i found this question worth reading. I'm really not sure about the accepted answer and the switch type and find me rather leaning on the side of Jon Skeet and Marc Gravell, which cannot be a bad thing in my opinion ;) Anyway you could be interested in reading it

Yes, you can and in some cases have to use this. This is called Abstract Factory , or some shape of it. Or Factory Method , which may fit best in your case.

The basic idea is to provide a function/class where you don't specify some concrete type, but you "signal" about desired type, and factory constructs the real object's instance.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM