Olivier Jacot-Desc абсолютно на верном пути (+1 за это).Единственное, чего не хватает в его ответе, - это загрузить правильные реализации из конфигурации.
Есть много способов сделать это, например, сохраняя имя типа в конфигурации, но вы также можете перейти кболее простой подход, такой как хранение простого логического значения в конфигурации.
IProvider providerX = GetProviderFromConfig();
IHandler handlerZ = GetHandlerFromConfig();
IPreProcessor preProcessorY = GetProcessorFromConfig();
var provider =
new ProviderWrapper(providerX, preProcessorY, handlerZ);
private static IProvider GetProviderFromConfig()
{
if (ConfigurationManager.AppSettings["provider"] == "mail")
{
return new MailProvider();
}
else
{
return new FtpProvider();
}
}
// implement GetHandlerFromConfig just like
// the GetProvider.
ОБНОВЛЕНИЕ
Когда у вас есть много типов для переключения между ними, сохраните имя типаможет быть лучшим выбором:
private static IProvider GetProviderFromConfig()
{
string typeName =
ConfigurationManager.AppSettings["provider"];
Type providerType = Type.GetType(typeName);
return (IProvider)
Activator.CreateInstance(providerType);
}
ОБНОВЛЕНИЕ 2
Вот пример того, как настроить это с Контейнером DI.Я использую Simple Injector (с extensions ), но подойдет любой контейнер (хотя способ его настройки будет отличаться для каждого контейнера):
Регистрация:
using SimpleInjector;
using SimpleInjector.Extensions;
Type providerType = Type.GetType(
ConfigurationManager.AppSettings["provider"]);
Type handlerType = Type.GetType(
ConfigurationManager.AppSettings["handler"]);
Type processorType = Type.GetType(
ConfigurationManager.AppSettings["preProcessor"]);
var container = new Container();
container.Register(typeof(IProvider), providerType);
container.Register(typeof(IHandler), handlerType);
container.Register(typeof(IPreProcessor), processorType);
Разрешение поставщика:
var provider = container.GetInstance<IPovider>();
Совет. Если вы используете инжектор конструктора, вам не нужно связывать типы вручную, контейнер сделает это за вас.Например, когда ваш MailProvider
выглядит следующим образом, контейнер может внедрить необходимые зависимости (IHandler
и IPreProcessor
) через конструктор:
public class MailProvider : IProvider
{
private readonly IHandler handler;
private readonly IPreProcessor preProcessor;
public MailProvider(IHandler handler,
IPreProcessor preProcessor)
{
this.handler = handler;
this.preProcessor = preProcessor;
}
public void SomeAction() { ... }
}