Инъекция зависимостей и фабрики - PullRequest
6 голосов
/ 27 июля 2011

Что такое достойный способ работы с условными подфабриками с помощью подхода DI. Сценарий - это объект загрузчика, который вставляется в запись, зависит от настроек этой записи. Первоначально я вводил контейнер IoC на завод и использовал его для разрешения на основе соглашений об именах. Тем не менее, я бы очень хотел содержать фабрику в чистоте от контейнера.

Фабрика вводится в класс, который загружает все настройки из базы данных, а затем использует фабрику для создания набора записей. Настройки определяют, какой загрузчик будет использоваться внутри данной записи.

Редактировать: изменение кода, чтобы лучше выделить фактический вопрос. Проблема в том, что несколько менеджеров баз данных должны поддерживаться одновременно, если бы это было не так, тогда это было бы просто. Тип менеджера базы данных определяется настройками записи, сохраненными для конкретной записи.

public class Entry : IEntry
{
     private ISomething loader;

     public Entry(ISomething something)
     {
         this.loader = something;
     }
}

public class EntryFactory : IEntryFactory
{
    IEntry BuildEntry(IEntrySetting setting)
    {
        //Use setting object to determine which database manager will be used
    }
}

public class EntryManager
{
    public EntryManager(IEntryFactory entryFactory)
    {
        var entrySettings = this.settings.Load();
        foreach(var setting in entrySettings)
        {
             this.entries.Add(entryFactory.BuildEntry(setting));
        }
    }
}

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

Ответы [ 2 ]

1 голос
/ 30 июля 2011

Что я обычно делаю, это создаю оболочку для моего DI-контейнера ... Что-то вроде IDependencyResolver ... И внедряю его в мои фабрики.Затем у вас может быть реализация, такая как StructureMapDependencyResolver, которая выполняет подъем.Мне это нравится больше, чем инъекция самого контейнера, потому что это позволяет мне почти мгновенно менять контейнеры DI.По крайней мере, мои заводы не должны меняться.

public interface IDependencyResolver
{
    T Resolve<T>();
}

public class UnityDependencyResolver : IDependencyResolver
{
    private readonly IUnityContainer _container;

    public UnityDependencyResolver(IUnityContainer container)
    {
        _container = container;
    }

    public T Resolve<T>()
    {
        return _container.Resolve<T>();
    }
}

Этот подход настолько гибок, что вы можете реализовать свои собственные решатели зависимостей и внедрить их вручную.

public class ManualDependencyResolver : IDependencyResolver
{
    public T Resolve<T>()
    {
        if (typeof(T)==typeof(ITransactionRepository))
        {
            return new CheckTransactionRespostory(new DataContext());
        }

        throw new Exception("No dependencies were found for the given type.");
    }
}
0 голосов
/ 28 июля 2011

Это зависит от того, что позволяет ваша структура DI, и вы не указали это. Используя Autofac делегированную регистрацию, я пришел к следующим решениям. Обратите внимание, что ILoaderFactory и IEntryFactory были заменены простыми Func<> фабриками в обоих случаях.

Решение 1 с использованием двух заводов:

public class EntryManager
{
    public EntryManager(Func<ILoader, IEntry> entryFactory, Func<Settings, ILoader> loaderFactory)
    {
        var entrySettings = this.settings.Load();
        foreach(var setting in entrySettings)
        {
            this.entries.Add(entryFactory(loaderFactory(setting)));
        }
    }
}

private static ILoader SelectLoader(IEntrySetting settings)
{
    // your custom loader selection logic
}

var builder = new ContainerBuilder();
builder.RegisterType<EntryManager>();
builder.RegisterType<Entry>().As<IEntry>();
builder.Register((c, p) => SelectLoader(p.TypedAs<IEntrySetting>()));
IContainer container = builder.Build();
container.Resolve<EntryManager>();

Решение 2, используя только одну фабрику:

public class EntryManager
{
    public EntryManager(Func<IEntrySetting, IEntry> entryFactory)
    {
        var entrySettings = this.settings.Load();
        foreach(var setting in entrySettings)
        {
            this.entries.Add(entryFactory(setting));
        }
    }
}

private static ILoader SelectLoader(IEntrySetting settings)
{
    // your custom loader selection logic
}

var builder = new ContainerBuilder();
builder.RegisterType<EntryManager>();
builder.Register((c, p) => new Entry(SelectLoader(p.TypedAs<IEntrySetting>()))).As<IEntry>();
IContainer container = builder.Build();
container.Resolve<EntryManager>();
...