在具有多个入口点的库中应用 IoC 设计
Applying IoC design in library with multiple entry points
我正在创建 NuGet 包,这将允许其消费者轻松地从 Azure send/receive 消息 topics/queues(加上一些特定于我需要的附加逻辑)。
包内部结构相当复杂,有很多依赖,计划用单元测试覆盖,因此决定使用 IoC 容器(Unity)。
问题是这个包有几个入口点(例如,对象图顶部的一个 class 用于主题操作,另一个 class 用于队列操作等)。
我读了很多关于 IoC 的类似文章,到处都在说正确的使用方法是 register/resolve/release 组合根目录中的容器(例如,在 Console 应用程序的 Main 方法中)。
但是如果我们有多个入口点怎么办(并且包消费者应该对内部包结构一无所知)?
我想了两个方案,两个都不太好看...
解决方案#1:
创建消费者将使用的额外 public "helper" class。对于每个 "entry point" 配置单独的容器并在每次需要时使用 "register/resolve/release" 模式构造所需的对象:
public class FooHelper
{
public static ITopicFoo CreateTopicManager()
{
IUnityContainer _container = new UnityContainer()
.RegisterType<ITopicFoo, TopicFoo>()
.RegisterType<ILotOtherDependencies, OtherDependencies>;
var topic = _container.Resolve<ITopicFoo>();
_container.Dispose();
return topic;
}
public static IQueueFoo CreateQueueManager()
{
IUnityContainer _container = new UnityContainer()
.RegisterType<IQueueFoo, QueueFoo>()
.RegisterType<ILotOtherDependencies, OtherDependencies>;
var queue = _container.Resolve<IQueueFoo>();
_container.Dispose();
return queue;
}
}
解决方案#2:
创建消费者将使用的额外 public "helper" class。使用所有信息配置容器,将其保存为静态 属性 并在需要时使用它来构造对象。
这看起来有点像 ServiceLocator 反模式,但并不多(除了 helper class 本身,没有人知道这个容器):
public class FooHelper
{
private static readonly IUnityContainer _container;
static FooHelper()
{
IUnityContainer _container = new UnityContainer()
.RegisterType<ITopicFoo, TopicFoo>()
.RegisterType<IQueueFoo, QueueFoo>()
.RegisterType<ILotOtherDependencies, OtherDependencies>;
}
public static ITopicFoo CreateTopicManager()
{
return _container.Resolve<ITopicFoo>();
}
public static IQueueFoo CreateQueueManager()
{
return _container.Resolve<IQueueFoo>();
}
}
这些解决方案在设计方面是否不错?有没有其他方法可以很好地处理这种情况?
或者这整个设计不是很好?
最后,在阅读 Mark Seemann 的博客后 post 我决定完全不在我的 NuGet 包中使用 IoC 容器。
相反,我以 DI 友好的方式设计了我的 NuGet 包(因此包消费者仍然可以使用 IoC 方法从其组合根构造所需的对象)。
对于不想关心 IoC 的包消费者,我准备了助手 类,它只是以默认方式构造所需的对象(如上面代码示例中的 "TopicManager" 或 "QueueManager")使用通常的 "new-new-..." 方法。
我正在创建 NuGet 包,这将允许其消费者轻松地从 Azure send/receive 消息 topics/queues(加上一些特定于我需要的附加逻辑)。
包内部结构相当复杂,有很多依赖,计划用单元测试覆盖,因此决定使用 IoC 容器(Unity)。
问题是这个包有几个入口点(例如,对象图顶部的一个 class 用于主题操作,另一个 class 用于队列操作等)。
我读了很多关于 IoC 的类似文章,到处都在说正确的使用方法是 register/resolve/release 组合根目录中的容器(例如,在 Console 应用程序的 Main 方法中)。 但是如果我们有多个入口点怎么办(并且包消费者应该对内部包结构一无所知)?
我想了两个方案,两个都不太好看...
解决方案#1:
创建消费者将使用的额外 public "helper" class。对于每个 "entry point" 配置单独的容器并在每次需要时使用 "register/resolve/release" 模式构造所需的对象:
public class FooHelper
{
public static ITopicFoo CreateTopicManager()
{
IUnityContainer _container = new UnityContainer()
.RegisterType<ITopicFoo, TopicFoo>()
.RegisterType<ILotOtherDependencies, OtherDependencies>;
var topic = _container.Resolve<ITopicFoo>();
_container.Dispose();
return topic;
}
public static IQueueFoo CreateQueueManager()
{
IUnityContainer _container = new UnityContainer()
.RegisterType<IQueueFoo, QueueFoo>()
.RegisterType<ILotOtherDependencies, OtherDependencies>;
var queue = _container.Resolve<IQueueFoo>();
_container.Dispose();
return queue;
}
}
解决方案#2:
创建消费者将使用的额外 public "helper" class。使用所有信息配置容器,将其保存为静态 属性 并在需要时使用它来构造对象。
这看起来有点像 ServiceLocator 反模式,但并不多(除了 helper class 本身,没有人知道这个容器):
public class FooHelper
{
private static readonly IUnityContainer _container;
static FooHelper()
{
IUnityContainer _container = new UnityContainer()
.RegisterType<ITopicFoo, TopicFoo>()
.RegisterType<IQueueFoo, QueueFoo>()
.RegisterType<ILotOtherDependencies, OtherDependencies>;
}
public static ITopicFoo CreateTopicManager()
{
return _container.Resolve<ITopicFoo>();
}
public static IQueueFoo CreateQueueManager()
{
return _container.Resolve<IQueueFoo>();
}
}
这些解决方案在设计方面是否不错?有没有其他方法可以很好地处理这种情况?
或者这整个设计不是很好?
最后,在阅读 Mark Seemann 的博客后 post 我决定完全不在我的 NuGet 包中使用 IoC 容器。
相反,我以 DI 友好的方式设计了我的 NuGet 包(因此包消费者仍然可以使用 IoC 方法从其组合根构造所需的对象)。
对于不想关心 IoC 的包消费者,我准备了助手 类,它只是以默认方式构造所需的对象(如上面代码示例中的 "TopicManager" 或 "QueueManager")使用通常的 "new-new-..." 方法。