Как использовать некоторых провайдеров с одинаковыми услугами? - PullRequest
0 голосов
/ 27 июня 2011

Я регистрирую Service & Provider с помощью некоторого инструмента IoC (например, StructreMap)

public interface IProvider
{
    void Load(int id);
}
public class Provider : IProvider
{
     public void Load(int id) {...} 
}
public interface IService
{
    void Load(int id);
}
public class Service : IService
{
    public Service(IProvider provider) { }
    public void Load(int id) { provider.Load(id); }
}

Теперь у меня есть другой провайдер

public class Provider2 : IProvider
{
    public void Load(int id) {...}
}

Я хочу зарегистрировать этого провайдера (Provider2) и получить экземпляр Service с Provider2 из инструмента IoC. Единственный способ сделать это - создать Service2, который унаследует от IService2, а последний унаследует от IService. И теперь я могу получить экземпляр типа IService2, который будет инициировать провайдера с Provider2.

public interface IService2 : IService
{ }
public class Service2 : IService2
{
    public Service2(IProvider2 provider) { }
    public void Load(int id) { provider.Load(id); }
}

У меня такой вопрос: для каждого нового провайдера мне нужно написать новый класс для службы, даже если функциональность службы должна оставаться прежней?

1 Ответ

1 голос
/ 27 июня 2011

Нет, вам не нужно этого делать.

Я бы посоветовал вам реализовать абстрактный шаблон фабрики для выбора правильной реализации провайдера в зависимости от значения, известного во время выполнения.

Для примера, пожалуйста, посмотрите здесь: http://alsagile.com/archive/2010/06/28/Abstract-Factory-and-IoC-Container-in-asp-net-MVC.aspx.

Это в контексте MVC, но может быть легко реализовано в других сценариях.

Пример:

Вы можете зарегистрировать свой сервис следующим образом (псевдокод):

x.For<IService>().Use<Service>();    
x.For<IProvider>().Use<Provider1>().Named("provider1");
x.For<IProvider>().Use<Provider2>().Named("provider2");

Вам нужен способ внедрить контейнер в вашу фабрику Abstract.Вы можете обернуть это, например, следующим образом:

public interface IProviderFactory
{    
    object GetInstance<IProvider>();    
    object GetNamedInstance<IProvider>(string key);
}

И реализация:

public class ProviderFactory : IProviderFactory
{     
    private readonly Container _container     
    public ProviderFactory (Container container)     
    {          
        _container = container;     
    }     
    ...
}

И настроить StructureMap для разрешения зависимостей в вашей абстрактной фабрике следующим образом:

x.For<IProviderFactory>.Use(new ProviderFactory(this));

Затем в вашу Службу вы должны добавить фабрику провайдера следующим образом

public class Service : IService
{
    private readonly IProviderFactory _providerFactory;

    public Service(IProviderFactory factory)
    {
        if (factory == null)
            throw new ArgumentNullException("factory", "providerfactory cannot be null");
        _proiderFactory = factory;
    }

    public void Load(string providerName)
    {
      var provider = _providerFactory.GetNamedInstance(providerName);
      // do some operation on provider
    }
}

Это должно работать.

...