Factory 和 IOC 在一起 - 如何同时使用两者?
Factory and IOC together - how to use then both?
所以我有这个应用程序,我在其中使用 IOC (autofac)。与此同时,我发现自己处于需要工厂的位置。在工厂内部,我创建了具有依赖关系的新对象 - 所以现在我想知道,我怎么能把它们结合起来呢?
public class SubscriptionHandlerFactory : ISubscriptionHandlerFactory
{
public ISubscriptionHandler GetProvider(StreamType streamType)
{
switch (streamType)
{
case StreamType.Rss:
return new RssSubscriptionHandler(null,null,null,null);
case StreamType.Person:
return new PersonSubscriptionHandler(null, null, null, null);
default:
throw new ArgumentOutOfRangeException(nameof(streamType), streamType, null);
}
}
}
你不能使用 IoC 永远抽象掉对象的实例化。在某些时候,您将不得不创建一个具体实例(在您的工厂或 IoC 容器内)
您可以将您的 autofac 容器注入您的工厂,或者,由于您的工厂本身实现了一个接口,那么您可以将不同版本的工厂注入到 class 可能需要的地方(例如,如果您需要一个用于单元测试目的的不同工厂)
我解决了。有点儿。因为我不想依赖 Autofac it self 我被撕裂了。但多亏了@martin-costello,我才意识到也许我不需要使用 autofac,而是在 IDependencyResolver 中构建,它不那么邪恶。由于我无法将 autofac 注册为 IDependencyResolver,因此我将 DependencyResolver 注册为 IDependencyResolver。又近了一步。由于注册发生在 autofac DependencyResolver.SetResolver 发生之前,我需要使用 Lazy,它最终解决了我的问题。
这是代码(或者至少是我发现的最佳解决方案)
// other registration
builder.RegisterType<RssSubscriptionHandler>();
builder.RegisterType<PersonSubscriptionHandler>();
// even more registration here
builder.RegisterType<SubscriptionHandlerFactory>()
.As<ISubscriptionHandlerFactory>()
.WithParameter(new TypedParameter(typeof(Lazy<IDependencyResolver>),
new Lazy<IDependencyResolver>(() => DependencyResolver.Current)));
然后工厂对此进行更改(清理之前):
public class SubscriptionHandlerFactory : ISubscriptionHandlerFactory
{
private readonly Lazy<IDependencyResolver> resolver;
public SubscriptionHandlerFactory(Lazy<IDependencyResolver> resolver)
{
this.resolver = resolver;
}
public ISubscriptionHandler GetProvider(StreamType streamType)
{
switch (streamType)
{
case StreamType.Rss:
return (ISubscriptionHandler)this.resolver.Value.GetService(typeof(RssSubscriptionHandler));
case StreamType.Person:
return (ISubscriptionHandler)this.resolver.Value.GetService(typeof(PersonSubscriptionHandler));
default:
throw new ArgumentOutOfRangeException(nameof(streamType), streamType, null);
}
}
}
目前这是我能够找出的 best/clean/less evil/less specific/abstract/whatever 解决方案。欢迎任何评论。
您可以使用 named and keyed service 并使用 IIndex<TKey, TService>
检索实例
注册可能如下所示:
builder.RegisterType<RssHandler>().Keyed<ISubscriptionHandler>(StreamType.Rss);
builder.RegisterType<PersonHandler>().Keyed<ISubscriptionHandler>(StreamType.Person);
builder.RegisterType<SubscriptionHandlerFactory>().As<ISubscriptionHandlerFactory>();
和这样的工厂:
public class SubscriptionHandlerFactory : ISubscriptionHandlerFactory
{
public SubscriptionHandlerFactory(IIndex<StreamType, ISubscriptionHandler> handlers)
{
this._handlers = handlers;
}
private readonly IIndex<StreamType, ISubscriptionHandler> _handlers;
public ISubscriptionHandler GetProvider(StreamType streamType)
{
return this._handlers[streamType];
}
}
所以我有这个应用程序,我在其中使用 IOC (autofac)。与此同时,我发现自己处于需要工厂的位置。在工厂内部,我创建了具有依赖关系的新对象 - 所以现在我想知道,我怎么能把它们结合起来呢?
public class SubscriptionHandlerFactory : ISubscriptionHandlerFactory
{
public ISubscriptionHandler GetProvider(StreamType streamType)
{
switch (streamType)
{
case StreamType.Rss:
return new RssSubscriptionHandler(null,null,null,null);
case StreamType.Person:
return new PersonSubscriptionHandler(null, null, null, null);
default:
throw new ArgumentOutOfRangeException(nameof(streamType), streamType, null);
}
}
}
你不能使用 IoC 永远抽象掉对象的实例化。在某些时候,您将不得不创建一个具体实例(在您的工厂或 IoC 容器内)
您可以将您的 autofac 容器注入您的工厂,或者,由于您的工厂本身实现了一个接口,那么您可以将不同版本的工厂注入到 class 可能需要的地方(例如,如果您需要一个用于单元测试目的的不同工厂)
我解决了。有点儿。因为我不想依赖 Autofac it self 我被撕裂了。但多亏了@martin-costello,我才意识到也许我不需要使用 autofac,而是在 IDependencyResolver 中构建,它不那么邪恶。由于我无法将 autofac 注册为 IDependencyResolver,因此我将 DependencyResolver 注册为 IDependencyResolver。又近了一步。由于注册发生在 autofac DependencyResolver.SetResolver 发生之前,我需要使用 Lazy,它最终解决了我的问题。
这是代码(或者至少是我发现的最佳解决方案)
// other registration
builder.RegisterType<RssSubscriptionHandler>();
builder.RegisterType<PersonSubscriptionHandler>();
// even more registration here
builder.RegisterType<SubscriptionHandlerFactory>()
.As<ISubscriptionHandlerFactory>()
.WithParameter(new TypedParameter(typeof(Lazy<IDependencyResolver>),
new Lazy<IDependencyResolver>(() => DependencyResolver.Current)));
然后工厂对此进行更改(清理之前):
public class SubscriptionHandlerFactory : ISubscriptionHandlerFactory
{
private readonly Lazy<IDependencyResolver> resolver;
public SubscriptionHandlerFactory(Lazy<IDependencyResolver> resolver)
{
this.resolver = resolver;
}
public ISubscriptionHandler GetProvider(StreamType streamType)
{
switch (streamType)
{
case StreamType.Rss:
return (ISubscriptionHandler)this.resolver.Value.GetService(typeof(RssSubscriptionHandler));
case StreamType.Person:
return (ISubscriptionHandler)this.resolver.Value.GetService(typeof(PersonSubscriptionHandler));
default:
throw new ArgumentOutOfRangeException(nameof(streamType), streamType, null);
}
}
}
目前这是我能够找出的 best/clean/less evil/less specific/abstract/whatever 解决方案。欢迎任何评论。
您可以使用 named and keyed service 并使用 IIndex<TKey, TService>
注册可能如下所示:
builder.RegisterType<RssHandler>().Keyed<ISubscriptionHandler>(StreamType.Rss);
builder.RegisterType<PersonHandler>().Keyed<ISubscriptionHandler>(StreamType.Person);
builder.RegisterType<SubscriptionHandlerFactory>().As<ISubscriptionHandlerFactory>();
和这样的工厂:
public class SubscriptionHandlerFactory : ISubscriptionHandlerFactory
{
public SubscriptionHandlerFactory(IIndex<StreamType, ISubscriptionHandler> handlers)
{
this._handlers = handlers;
}
private readonly IIndex<StreamType, ISubscriptionHandler> _handlers;
public ISubscriptionHandler GetProvider(StreamType streamType)
{
return this._handlers[streamType];
}
}