依赖注入和工厂

时间:2011-07-27 19:25:54

标签: c# dependency-injection factory

使用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 个答案:

答案 0 :(得分:1)

我通常做的是为我的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.");
    }
}

答案 1 :(得分:0)

这取决于您的DI框架允许的内容,而您没有指定它。使用Autofac基于委托的注册,我找到了以下解决方案。请注意,在这两种情况下,ILoaderFactoryIEntryFactory都已由简单的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>();