使用依赖注入有什么缺点?
我试图在工作中引入DI作为一种模式,我们的一位主要开发人员想知道:使用依赖注入模式的缺点是什么 - 如果有的话?
注意我在这里寻找一个 - 如果可能的话 - 详尽的列表,而不是关于该主题的主观讨论。
澄清 :我在谈论依赖注入模式(请参阅Martin Fowler的本文),而不是基于XML(如Spring)或基于代码(如Guice)或“自动滚动”的特定框架。
编辑 :在这里进行一些伟大的进一步讨论/咆哮/辩论。
几点:
通常,解耦的好处使得每个任务更易于阅读和理解,但是增加了编排更复杂任务的复杂性。
您经常使用面向对象的编程,样式规则以及其他所有方面都遇到同样的基本问题。 事实上,这可能 - 很常见 - 做太多的抽象,并增加太多的间接性,并且通常在过分和错误的地方应用好的技术。
您应用的每种模式或其他构造都会带来复杂性 抽象和间接消散了周围的信息,有时会将不相关的细节排除在外,但同样有时会使得难以准确理解发生了什么。 你应用的每一条规则都会带来灵活性,排除可能只是最佳方法的选项。
关键是编写能够完成这项工作的代码,并且功能强大,可读性强,易于维护。 你是一名软件开发人员 - 不是象牙塔建造者。
相关链接
http://thedailywtf.com/Articles/The_Inner-Platform_Effect.aspx
http://www.joelonsoftware.com/articles/fog0000000018.html
可能最简单的依赖注入形式(不要笑)是一个参数。 从属代码依赖于数据,并且通过传递参数来注入数据。
是的,这很愚蠢,并没有解决依赖注入的面向对象的问题,但功能程序员会告诉你(如果你有第一类函数),这是你需要的唯一一种依赖注入。 这里的要点是举一个微不足道的例子,并展示潜在的问题。
让我们来看看这个简单的传统函数 - C ++语法在这里并不重要,但我必须拼写它......
void Say_Hello_World ()
{
std::cout << "Hello World" << std::endl;
}
我有一个我想要提取并注入的依赖关系 - 文本“Hello World”。 很简单...
void Say_Something (const char *p_text)
{
std::cout << p_text << std::endl;
}
如何比原来更不灵活? 那么,如果我决定输出应该是unicode呢? 我可能想从std :: cout切换到std :: wcout。 但这意味着我的字符串必须是wchar_t,而不是char。 要么每个调用者都被改变,要么(更合理地),旧的实现被替换为转换字符串并调用新实现的适配器。
这就是维护工作,如果我们保留了原版,那就不需要了。
如果它看起来微不足道,请从Win32 API中查看这个实际功能...
http://msdn.microsoft.com/en-us/library/ms632680%28v=vs.85%29.aspx
这是12个“依赖”来处理。 例如,如果屏幕分辨率真的很大,也许我们需要64位坐标值 - 另一个版本的CreateWindowEx。 是的,已经有一个更旧的版本仍然存在,这可能会映射到幕后的新版本。
http://msdn.microsoft.com/en-us/library/ms632679%28v=vs.85%29.aspx
这些“依赖关系”不仅仅是原始开发人员的问题 - 每个使用该接口的人都必须查找依赖关系是什么,如何指定它们以及它们的含义,并确定为他们的应用程序做些什么。 这就是“明智的默认”可以让生活变得更简单的地方。
原则上,面向对象的依赖注入没有区别。 编写类是开销,无论是源代码文本还是开发人员时间,如果根据某些从属对象规范编写该类以提供依赖关系,则依赖对象将被锁定为支持该接口,即使需要取代该对象的实现。
这些都不应该被认为是声称依赖注入是不好的 - 远非如此。 但是任何好的技术都可以被过度应用,并且放在错误的地方。 就像不是每个字符串都需要被提取出来并转换成参数一样,并不是每个低级行为都需要从高级对象中提取出来,并转化为可注入的依赖关系。
这是我自己的最初反应:基本上任何模式的相同缺点。