什么时候不使用IoC和DI?

时间:2009-09-01 15:05:03

标签: design-patterns dependency-injection inversion-of-control methodology

我看到很多文章都说IoC和DI有多棒,而且没有关于它为什么不那么好的文章,因为它可以使代码更复杂。我还看到IoC不应该是代码的核心部分,而是更多的库和插件。文章通常只是一个小参考,这两个模式如何使代码更复杂,但在细节上没有多少。这是我的问题 - 特别是你不应该使用这些模式吗?

这是一个很好的主题:What is Inversion of Control?。如果你向下看,有一篇关于拼写检查的帖子和另一篇关于IoC如果只是一个拼写检查器可能不是很好用的帖子。作为一般准则,如果不使用IoC,我只有一个具体的接口类?意思是,我有IMyClass。然后只有实现IMyClass的具体MyClassA。我为什么要在那里使用IoC?

如果我有MyClassA,MyClassB和MyClassC,每个都实现IMyClass,那些可能是IoC正确的候选者吗?

在同一个主题中,有谁知道这篇文章的含义:

  • 控制倒置=婚姻
  • IOC Container = Wife

8 个答案:

答案 0 :(得分:32)

关于只有一个接口实现的问题。使用IoC时,使用接口仍然很有用。使用模拟这些接口创建真正的单元测试(不依赖于接口实现正常工作)会容易得多。使用IoC的核心是使代码更容易测试。因此,如果您不想测试,请不要使用IoC,或者在没有测试的情况下已经有更好的测试计划。

恕我直言, DI和IoC复杂性的增加是通过更容易测试和更少耦合的代码来实现的。更容易隔离问题并进行未来的更改。您也可以更好地控制其行为。

我可以看到何时不使用IoC容器(因为它会导致配置开销)。这可能发生在小项目上,您可以手动执行,而不是使用容器。但是,除非你不打算测试你的代码,否则我看不出使用DI会有多大损失......

答案 1 :(得分:21)

控制倒置=婚姻

IOC Container = Wife

婚姻是已知模式的定义 - 妻子是该模式的实现; - )

伯纳德。

答案 2 :(得分:15)

使用IoC容器不是决定在单个类的级别进行 - 在任何项目中,您将拥有容器创建的类型。

复杂性权衡是:

  • 对于少量组件,IoC容器会增加一些开销
  • 随着应用程序中组件数量的增加:
    • 如果没有IoC容器,添加新组件或重构往往会变得越来越困难
    • 使用IoC容器,添加新组件或重构保持不变:您只需要担心要添加或更改的组件的直接依赖性。

如果您曾经历过即使设计良好且维护良好的代码库变得无法管理的现象,您也会遇到IoC容器解决的问题。

答案 3 :(得分:11)

来自the Castle Project

  

为什么我不使用它?

     

你不应该使用Inversion   控制容器,如果你不是   熟悉这些概念,如果你   没有意识到他们尝试的问题   解决。

     

另外,根据尺寸和   项目的复杂性,IoC   容器可能有点矫枉过正。较喜欢   在大中型项目中使用它。

答案 4 :(得分:6)

关于IoC的抱怨很容易理解:IoC将简单的东西变成了复杂的东西。假设你想对列表的每个元素做一些事情(伪代码):

for each i in list:
    do_something(i)
从本质上讲,IoC正在将循环迭代的责任转移给其他人。因此,我们最终得到了更像这样的东西:

ioc = new IocContainer()
ioc.register_callback(do_something)
ioc.go()

请注意,即使在这种简单的形式中,代码也比原始代码长......而且这还不包括IocContainer的实现。

然后,以其最好的形式,IocContainer可以静态初始化,或者通过静态Main()函数或隐藏的其他地方进行初始化,并根据迭代XML文件的其他代码自动调用register_callback()函数列出了所有do_something()函数和(有时)列表中的内容以进行迭代。

是的,XML文件使您的软件更易于配置!对?您只需更改一个简单的文本文件即可更改列表中的某些内容!

具有讽刺意味的是,你的源代码现在更长并且更难理解,它取决于各种新的,可能有错误的库(包括IocContainer和XML解析器),而且你'实际上,维护起来比较困难:XML代码比原始简单的源代码循环(无论循环写入的语言)更难以理解和编辑更难。你也很少控制你想要如何进行迭代(排序或未排序?深度优先或广度优先?),因为IocContainer正在承担你的责任。

对于像插件这样的东西,使用IoC是有意义的,因为主应用程序的逻辑可以控制执行过程,并且可以在这里和那里向插件寻求帮助。这被称为“提供钩子”,并且比IoC术语要长得多。

对于像单元测试这样的东西(我经常看到它被抛出的地方),IoC通常被证明是无益的,因为你的测试需要能够模拟各种奇怪的情况,而IoC只是不断妨碍了这一点。

IoC的基本假设是加载数据和循环通过某种程度上是困难的并且需要被删除;这种假设不正确,因为它无论如何都不会超过几行(或者你可以将它移到一个单独的函数中),即使它确实保存了代码,也会降低你的灵活性。

答案 5 :(得分:4)

IoC / DI不是技术,它们是范例。你的问题类似于问“什么时候不应该使用面向对象的编程?”这是一个比您的代码库中的单个单元更大的决定。

要回答您的具体问题,如果您没有足够的类来手动合理地构建对象图,并且您没有多次重复相同的对象图实例化,那么您可能不需要IoC容器。

答案 6 :(得分:2)

我想我会说简单的答案只在你想要进行单元测试的对象上使用IoC。

如果这看起来很轻浮,我很抱歉,这是因为编写的代码没有考虑单元测试。我真的不明白为什么会增加复杂性 - 如果我需要知道实际的对象类型,我肯定可以在运行时打印出类。

答案 7 :(得分:0)

本文解决了您的问题“您应该具体使用这些模式吗?”并提供有关您的评论的详细示例“两种模式([IoC和DI])可以使代码更复杂”:

http://java.dzone.com/articles/beyond-injection-concerns-ioc

总结本文的两个要点:

  1. 在封装非常重要的情况下,不应使用IoC / DI。
  2. 您不应该使用IoC / DI,因为您无法通过使用IoC / DI的优势来证明通过使用IoC / DI而增加复杂性的具体示例。