我明白依赖注入本身的好处。让我们以 Spring 为例。我也理解其他 Spring 特性的好处,比如 AOP、不同类型的助手等等。我只是想知道,XML 配置的好处是什么,比如:
<bean id="Mary" class="foo.bar.Female">
<property name="age" value="23"/>
</bean>
<bean id="John" class="foo.bar.Male">
<property name="girlfriend" ref="Mary"/>
</bean>
与普通的旧 Java 代码相比,例如:
Female mary = new Female();
mary.setAge(23);
Male john = new Male();
john.setGirlfriend(mary);
这是更容易调试,编译时间检查,可以理解的任何人谁只知道 Java。 那么,依赖注入框架的主要目的是什么呢
更新:
以防万一
IService myService;// ...
public void doSomething() {
myService.fetchData();
}
如果 myService 有多个实现,IoC 框架如何猜测我想要注入的是哪个实现?如果给定接口只有一个实现,并且我让 IoC 容器自动决定使用它,那么在出现第二个实现之后,它将被中断。如果故意只有一个接口的可能实现,那么就不需要注入它。
看到 IoC 的一小部分配置显示了它的好处,这将是非常有趣的。我已经使用 Spring 有一段时间了,我不能提供这样的例子。我可以展示单行代码,它们演示了 hibernate、 dwr 和我使用的其他框架的优点。
更新2:
我意识到 IoC 配置可以在不重新编译的情况下进行更改。这真的是个好主意吗?我可以理解,当有人想更改数据库凭据而不重新编译-他可能不是开发人员。在您的实践中,除了开发人员以外的其他人多久更改一次 IoC 配置?我认为对于开发人员来说,没有必要重新编译那个特定的类,而是改变配置。对于非开发人员,您可能希望让他的生活更轻松,并提供一些更简单的配置文件。
更新3:
接口及其具体实现之间映射的外部配置
有什么好处可以让它扩展呢?你没有把所有的代码都放在外部,但是你肯定可以——只要把它放在 ClassName.java.txt 文件中,在飞行中手动读取和编译——哇,你避免了重新编译。为什么要避免编译? !
您节省了编码时间,因为您以声明方式提供映射,而不是在过程代码中提供映射
我知道有时声明式方法可以节省时间。例如,我只声明一次 bean 属性和 DB 列之间的映射,并且 hibernate 在加载、保存、基于 HSQL 构建 SQL 等时使用这种映射。这就是声明式方法的工作原理。对于 Spring (在我的示例中) ,声明有更多的行,并且具有与对应代码相同的表达能力。如果有一个例子,当这样的声明是短于代码-我想看到它。
控制反转原则允许简单的单元测试,因为你可以用假的实现替换真的实现(比如用内存中的数据库替换 SQL 数据库)
我确实理解控制反转的好处(我更愿意把这里讨论的设计模式称为依赖注入,因为 IoC 更通用——有很多种控制,而我们只颠倒了其中的一种——初始化控制)。我在问为什么有人需要编程语言以外的东西来做这件事。我完全可以用代码来替换真实的实现。这段代码将表达与配置相同的内容——它只是用假值初始化字段。
mary = new FakeFemale();
我明白 DI 的好处。我不明白与配置执行相同操作的代码相比,外部 XML 配置有什么好处。我不认为应该避免编译——我每天都在编译,而且我还活着。我认为 DI 的配置是声明性方法的坏例子。如果以不同的方式多次使用 AND 声明,则声明可能非常有用——比如 hibernate cfg,其中 bean 属性和 DB 列之间的映射用于保存、加载、构建搜索查询等。SpringDI 配置可以很容易地转换为配置代码,就像在这个问题的开头,难道不是吗?它只用于 bean 初始化,不是吗?这意味着声明式方法在这里没有添加任何内容,对吗?
当我声明 hibernate 映射时,我只是给 hibernate 一些信息,并且它基于这些信息工作——我不告诉它要做什么。对于春天,我的宣言告诉春天该做什么——那么为什么要宣布,为什么不直接去做呢?
最后更新:
伙计们很多答案都在告诉我依赖注入我知道这很好。
问题在于 DI 配置的目的而不是初始化代码——我倾向于认为初始化代码更短更清晰。
到目前为止,我得到的唯一答案是,当配置发生变化时,它避免了重新编译。我想我应该发布另一个问题,因为它是我的一个大秘密,为什么编译应该避免在这种情况下。