对 IoC 的抱怨很容易理解:IoC 把简单的事情变成了复杂的事情。假设您想对列表的每个元素做一些事情(在伪代码中):
for each i in list:
do_something(i)
IoC 本质上是将循环迭代的责任转移给其他人。因此,我们最终会得到更像这样的东西:
ioc = new IocContainer()
ioc.register_callback(do_something)
ioc.go()
请注意,即使在这种简单的形式中,代码也比原来的要长……这还不包括 IocContainer 的实现。
然后,在其最奇特的形式中,IocContainer 可以静态初始化,也可以通过静态 Main() 函数或其他隐藏的地方进行初始化,并且 register_callback() 函数会根据其他一些代码自动调用,这些代码遍历列出所有的 XML 文件您的 do_something() 函数和(有时)甚至要遍历的列表的内容。
是的,XML 文件使您的软件更具可配置性!正确的?只需更改一个简单的文本文件,您就可以更改对列表执行的操作!
除了具有讽刺意味的是,您的源代码现在变得更长且更难理解,它依赖于各种新的、可能有问题的库(包括 IocContainer 和 XML 解析器),而您实际上使维护变得更加困难:XML 代码比原始的简单源代码循环更难理解和编辑(无论循环是用什么语言编写的)。您对如何进行迭代(排序或未排序?深度优先还是广度优先?)的控制也较少,因为 IocContainer 正在从您身上承担这一责任。
对于插件之类的东西,使用 IoC 是有意义的,因为主应用程序控制执行过程是合乎逻辑的,并且只是在这里和那里向插件寻求帮助。这被称为“提供挂钩”,并且比 IoC 术语存在的时间要长得多。
对于单元测试之类的事情(我经常看到它到处乱扔),IoC 通常证明是无用的,因为您的测试需要能够模拟各种各样的奇怪情况,而 IoC 只是不断地进入这种方式。
IoC 的基本假设是加载数据和循环遍历在某种程度上是困难的,需要被抽象掉;这个假设是不正确的,因为它永远不会超过几行(或者你可以将它移动到一个单独的函数中),即使它确实节省了代码,它也会降低你的灵活性。