在 SO 上似乎存在关于使用单例的耻辱。我个人从来没有买过它,但出于开放的心态,我正在尝试尝试 IoC 概念作为替代方案,因为坦率地说,我对我的日常工作感到厌倦,并且想尝试一些不同的东西。如果我对 IoC 概念的解释不正确或有误,请原谅我。
情况是这样的:我正在构建一个简单的 HttpListener
基于 Windows 服务中的 Web 服务器,它利用插件模型来确定应如何根据请求的 URL 处理请求(就像其他询问 HttpListener
的人一样)。我发现插件的方法是查询已配置的目录以查找装饰有 HttpModuleAssemblyAttribute
的程序集。 .这些程序集可以包含 0 个或多个 IHttpModule
另外装饰有HttpModuleAttribute
的 child 用于指定模块的名称、版本、人类可读的描述和各种其他信息。像这样的东西:
[HttpModule(/*Some property values that matter */)]
public class SimpleHttpModule : IHttpModule
{
public void Execute(HttpListenerContext context)
{
/* Do Something Special */
}
}
当 HttpModule
被发现我通常会将其添加到 Dictionary<string, Type>
object who 的唯一目的是跟踪我们知道的模块。这本词典通常会存在于我的单例的变体中,它呈现出一个 ACE style Singleton 的角色。 (这是我学习单例的 C++ 时代留下的遗产)。
现在我正在尝试实现的是使用(我对)一般 IoC 概念的类似内容。基本上我有一个 AppService
收藏地点IAppService
定义为:
public interface IAppService : IDisposable
{
void Initialize();
}
还有我的插件AppService
看起来像:
[AppService("Plugins")]
internal class PluginAppService : IAppService, IDictionary<string, Type>
{
/* Common IDictionary Implementation consisting of something like: */
internal Type Item(string modName)
{
Type modType;
if (!this.TryGetValue(modName, out modType)
return null;
return modType;
}
internal void Initialize()
{
// Find internal and external plug-ins and add them to myself
}
// IDisposable clean up method that attempts to dispose all known plug-ins
}
然后在服务期间OnStart
我实例化了一个 AppServices
的实例这是本地已知的,但传递给所有实例化插件的构造函数:
public class AppServices : IDisposable, IDictionary<string, IAppService>
{
/* Simple implementation of IDictionary */
public void Initialization()
{
// Find internal IAppService implementations, instantiate them (passing this as a constructor parameter), initialize them and add them to this.
// Somewhere in there would be something like
Add(appSvcName, appSvc);
}
}
我们曾经的单一方法实现变成了抽象实现 + 子构造器:
[HttpModule(/*Some property values that matter */)]
public abstract class HttpModule : IHttpModule
{
protected AppServices appServices = null;
public HttpModule(AppServices services)
{
appServices = services;
}
public abstract void Execute(HttpListenerContext context);
}
[HttpModule(/*Some property values that matter */)]
public class SimpleHttpModule : HttpModule
{
public SimpleHttpModule(AppServices services) : base(services) { }
public override void Execute(HttpListenerContext context)
{
/* Do Something Special */
}
}
并且对常用应用程序服务的任何访问都变成:
var plugType = appServices["Plugins"][plugName];
而不是:
var plugType = PluginManager.Instance[plugName];
我是否遗漏了一些可以简化这一切的基本 IoC 概念,或者所有这些额外的代码真的有好处吗?在我的世界中,单例是简单的生物,允许整个程序中的代码访问所需的(相对静态的)信息(在本例中为类型)。
更明确地提出问题:
- 这是转换为 IoC/DI 概念的 Factory Singleton 的有效实现吗?
- 如果是,那么需要额外代码和强加看似更笨重的 API 的返回/好处在哪里?
最佳答案
IoC 是一个通用术语。依赖注入(inject)是当今更受欢迎的术语。
依赖注入(inject)在某些情况下确实很出色。首先,它定义了一个比具有硬编码依赖实例的解决方案更可测试的架构。单例很难进行单元测试,因为它们是静态的,静态数据无法“卸载”。
其次,Dependency Injection不仅仅实例化你想要的类型,而是所有的依赖类型。因此,如果 A 类需要 B 类,B 类需要 C 类和 D 类,那么一个好的 DI 框架将自动创建所有依赖项,并控制它们的生命周期(例如,使它们在单个 Web 请求的生命周期内存在)。
DI 容器可以被认为是可以实例化任何类型对象的通用工厂(只要它被正确配置并满足 DI 框架的要求)。所以你不必编写自定义工厂。
与任何通用解决方案一样,它旨在为 90% 的用例提供他们需要的东西。当然,您可以在每次需要集合时创建一个手工制作的自定义链表数据结构,但 90=% 的时间一个通用的就可以正常工作。 DI 和自定义工厂也是如此。
关于c# - IoC 对我的工厂单例的好处,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9074155/