使用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));
}
}
}
我曾考虑让子工厂在主要工厂注册并以这种方式解决,但我不知道是否有更好的方法。
答案 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基于委托的注册,我找到了以下解决方案。请注意,在这两种情况下,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>();