有人能详细解释一下如何使用IOC容器吗?

我通过参数和构造函数广泛使用dependency injection。 我理解这个学位的原则并对此感到满意。 在我的大型项目中,我最终注入了太多的依赖项(任何达到双重数字的东西都感觉很大 – 我喜欢“通心粉代码”这个术语)。

因此,我一直在考虑IOC容器。 我已经阅读了一些关于它们的文章,到目前为止我没有看到它的好处。 我可以看到它如何协助发送相关对象组或一次又一次地获取相同类型。 我不确定他们如何在我的项目中帮助我,我可能有超过一百个类实现相同的界面,并且我在不同的顺序中使用它们。

那么,任何人都能指出一些不仅描述IOC容器概念的好文章(最好不要特别夸大其中),还要详细说明它们在这类项目中如何使我受益,以及它们如何适合我的范围。一个大型的建筑?

我希望看到一些非语言特定的东西,但如果有必要我的首选语言是C#。

控制反转主要是关于依赖关系管理和提供可测试代码。 从经典方法来看,如果一个类具有依赖性,那么自然趋势是赋予具有依赖性的类直接控制其依赖性。 这通常意味着具有依赖关系的类将在构造函数中“新建”其依赖关系,或者在其方法中按需提供。

控制反转只是……它反转了创建依赖关系的内容,将该进程外化并将它们注入具有依赖关系的类中。 通常,创建依赖关系的实体就是我们所说的IoC容器,它不仅负责创建和注入依赖关系,还负责管理它们的生命周期,确定它们的生活方式(更多关于这一点),并提供多种选择其他能力。 (这是基于Castle MicroKernel / Windsor,它是我选择的IoC容器……它写得很结实,非常实用,可扩展。如果你有更简单的需求,比如Ninject,Microsoft Unity和其他IoC容器更简单。 Spring.NET。)

考虑您有一个可以在本地上下文或远程上下文中使用的内部应用程序。 根据某些可检测因素,您的应用程序可能需要加载服务的“本地”实现,而在其他情况下,可能需要加载服务的“远程”实现。 如果您遵循经典方法,并直接在具有这些依赖关系的类中创建依赖关系,那么该类将被迫打破关于软件开发的两个非常重要的规则:关注点分离和单一责任。 您跨越了关注的界限,因为您的类现在关注其内在目的,以及确定应该创建哪些依赖项以及如何创建它们的关注点。 该类现在还负责许多事情,而不是一件事,并且有很多理由要改变:它的内在目的改变,它的依赖关系改变的创建过程,它找到远程依赖关系改变的方式,它的依赖关系可能需要什么依赖关系等

通过反转依赖关系管理,您可以改进系统体系结构并维护SoC和SR(或者,当您以前由于依赖关系而无法实现时)。由于外部实体IoC容器现在控制着依赖关系的方式。创建和注入,您还可以获得额外的function。 容器可以管理依赖项的生命周期,以更灵活的方式创建和销毁它们,从而提高效率。 您还可以管理对象的生活方式。 如果您有一种非常频繁地创建,使用和返回的依赖关系,但是很少或没有状态(例如工厂),您可以为它们提供池化生活方式,这将告诉容器自动创建该特定依赖项类型的对象池。 许多生活方式都存在,像温莎城堡这样的容器通常会让你有能力创造自己的生活方式。

更好的IoC容器,如Castle Windsor,也提供了很多可扩展性。 默认情况下,Windsor允许您创建本地类型的实例。 它可以创建扩展Windsor类型创建function的工具,以便在运行时动态创建Web服务代理和WCF服务主机,无需使用svcutil等工具手动或静态创建它们(这是我最近刚才做的事情) 。)许多工具可以使IoC支持现有的框架,如NHibernate,ActiveRecord等。

最后,IoC强制执行一种编码方式,以确保单元可测试的代码。 使代码单元可测试的关键因素之一是外部化依赖关系管理。 如果没有提供替代(模拟,存根等)依赖关系的能力,单独测试单个“单元”代码是一项非常困难的任务,使集成测试成为自动测试的唯一替代方式。 由于IoC要求您的类通过注入(通过构造函数,属性或方法)接受依赖关系,因此每个类通常(如果不是总是)被简化为单独的关联责任和完全可模拟的依赖关系。

IoC =更好的架构,更强的凝聚力,更好的关注点分离,更容易减少到单一职责的类,易于配置和可互换的依赖项(通常无需重新编译代码),灵活的依赖生活方式和生命周期管理,以及单元可测试代码。 IoC是一种生活方式……一种哲学,一种解决常见问题和满足SoC和SR等关键最佳实践的方法。

甚至(或者更确切地说)具有数百种不同的单一接口实现,IoC可以提供很多function。 让你的脑袋完全缠绕它可能需要一段时间,但是一旦你完全理解IoC是什么以及它能为你做什么,你就永远不会想要以任何其他方式做任何事情(除了嵌入式系统开发……) )

如果你有超过一百个类实现一个通用接口,IoC将无济于事,你需要一个工厂。 这样,您可以执行以下操作:

public interface IMyInterface{ //... } public class Factory{ public static IMyInterface GetObject(string param){ // param is a parameter that will help the Factory decide what object to return // (that is only an example, there may not be any parameter at all) } } //... // You do not depend on a particular implementation here IMyInterface obj = Factory.GetObject("some param"); 

在工厂内部,您可以使用IoC容器来检索对象(如果您愿意),但是您必须注册实现给定接口的每个类并将它们与某些键关联(并将这些键用作GetObject中的参数) () 方法)。

当您必须检索实现不同接口的对象时,IoC特别有用:

 IMyInteface myObject = Container.GetObject(); IMyOtherInterface myOtherObject Container.GetObject(); ISomeOtherInterface someOtherObject = Container.GetObject(); 

看到? 只有一个对象可以获得几个不同类型的对象而没有键(接口本身就是键)。 如果你需要一个对象来获得几个不同的对象,但是所有对象都实现了相同的接口,那么IoC对你的帮助就不大了。

在过去的几个星期里,我已经从dependency injection到了Castle的全面控制反转,所以我理解你的问题来自哪里。

我不想使用IOC容器的一些原因:

  1. 这是一个不会增长那么多的小项目。 如果构造函数和对这些构造函数的调用之间存在1:1的关系,那么使用IOC容器不会减少我必须编写的代码量。 在你发现自己第二次复制和粘贴完全相同的“var myObject = new MyClass(s​​omeInjectedDependency)”之前,你不会违反“不要重复自己”。

  2. 我可能必须调整现有代码以便于加载到IOC容器中。 这可能是没有必要的,直到你进入一些较酷的面向方面的编程function,但如果你忘记使方法虚拟,密封该方法的类,它没有实现一个接口,你’由于存在依赖性而使这些更改变得不舒服,然后使切换不那么吸引人。

  3. 它为我的项目 – 以及我的团队添加了额外的外部依赖项。 我可以说服我团队的其他成员构建他们的代码以允许DI膨胀,但我目前是唯一一个知道如何使用Castle的人。 对于规模较小,不太复杂的项目,这不会成为问题。 对于较大的项目(具有讽刺意味的是,这将从IOC容器中获得最多的收益),如果我不能很好地使用IOC容器传播,那么在我的团队中变得特立独行并不会对任何人有所帮助。

我不想回到普通DI的一些原因:

  1. 我可以添加或删除记录到我的任意数量的类,而无需添加任何类型的跟踪或日志记录语句。 能够让我的课程在不改变这些课程的情况下与其他function交织在一起,是非常强大的。 例如:

    记录: http : //ayende.com/Blog/archive/2008/07/31/Logging–the-AOP-way.aspx

    交易: http : //www.codeproject.com/KB/architecture/introducingcastle.aspx (跳到交易部分)

  2. 至少,Castle在将类连接到依赖项时非常有帮助,回去会很痛苦。

例如,缺少与Castle的依赖关系:

“无法创建组件’MyClass’,因为它具有满足的依赖性。服务正在等待以下依赖项:

服务: – 未注册的IMyService。“

缺少没有Castle的依赖项:

对象引用未设置为对象的实例

Dead Last:通过编辑Xml文件在运行时交换注入服务的能力。 我的看法是,这是最苛刻的function,但我认为它只是锦上添花。 我宁愿用代码连接我的所有服务,但我相信我将来会遇到头疼的问题。

我承认 – 作为国际奥委会和城堡的新手 – 我可能只是表面上看,但到目前为止,我真的很喜欢我所看到的。 我觉得我用它构建的最后几个项目真的能够对我公司日常出现的不可预测的变化做出反应,这种感觉我以前从未有过。

我没有链接,但可以为您提供一个示例:

您有一个Web控制器需要调用具有数据访问层的服务。

现在,我把它放在你的代码中,你在编译时构建这些对象。 您正在使用一个不错的设计模式,但如果您需要更改说dao的实现,您必须进入代码并删除设置此依赖关系的代码,重新编译/测试/部署。 但是如果您要使用IOC容器,则只需更改配置中的类并重新启动应用程序。

Jeremy Frey错过了使用IOC容器的最大原因之一:它使您的代码更容易进行模拟和测试。

鼓励使用接口还有许多其他好处:更好的分层,更容易动态生成代理,如声明式事务,面向方面的编程和远程处理。

如果你认为IOC只对替换“new”的呼叫有好处,你就不会得到它。

IoC容器通常执行dependency injection,这在某些项目中并不是什么大问题,但是一些提供IoC容器的框架提供了其他值得使用它们的服务。 例如,Castle除了IoC容器之外还有一个完整的服务列表。动态代理,事务管理和NHibernate设施都是其中的一部分。 然后我认为您应该将IoC contianers视为应用程序框架的一部分。

这就是我使用IoC容器的原因:1。写unit testing会更容易。实际上你可以编写不同的配置来做不同的事情2.为不同的场景添加不同的插件(例如,针对不同的客户)3。接受类添加不同的方面我们的代码。 4.由于我们使用的是NHibernate,Castle的事务管理和NHibernate设备在开发和维护代码方面非常有用。 这就像我们的应用程序的每个技术方面都是使用应用程序框架来处理的,我们有时间考虑客户真正想要的东西。