我理解依赖注入本身的好处.我们以Spring为例.我也了解其他Spring功能的好处,如AOP,不同类型的帮助等等.我只是想知道,XML配置有哪些好处,例如:
与普通的旧java代码相比,例如:
Female mary = new Female(); mary.setAge(23); Male john = new Male(); john.setGirlfriend(mary);
这是更容易调试,编译时间检查,任何只知道java的人都可以理解.那么依赖注入框架的主要目的是什么?(或显示其好处的一段代码.)
更新:
如果是
IService myService;// ... public void doSomething() { myService.fetchData(); }
如果有多个,IoC框架如何猜测我希望注入哪个myService实现?如果只有一个给定接口的实现,并且我让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的配置是声明性方法的坏例子.如果声明一次并且以不同方式多次使用声明,则声明可能很有用 - 例如hibernate cfg,其中bean属性和DB列之间的映射用于保存,加载,构建搜索查询等.Spring DI配置可以很容易地转换为配置代码,就像在这个问题的开头,它可以吗?它只用于bean初始化,不是吗?这意味着声明式方法不会在这里添加任何内容,是吗?
当我声明hibernate映射时,我只是给hibernate一些信息,它基于它工作 - 我不告诉它该怎么做.在春天的情况下,我的宣言告诉春天应该做什么 - 所以为什么要宣布它,为什么不这样做呢?
最后更新:
伙计们,很多答案告诉我有关依赖注入的问题,我知道这很好.问题是关于DI配置的目的而不是初始化代码 - 我倾向于认为初始化代码更短更清晰.到目前为止,我得到的唯一答案是,当配置发生变化时,它避免了重新编译.我想我应该发布另一个问题,因为对我来说这是一个很大的秘密,为什么在这种情况下应该避免编译.
对我自己而言,使用IoC(并利用外部配置)的主要原因之一是围绕以下两个方面:
测试
生产维护
测试
如果将测试分成3个场景(在大规模开发中相当正常):
单元测试
集成测试
黑盒测试
您要做的是针对最后两个测试场景(Integration&Black box),不重新编译应用程序的任何部分.
如果您的任何测试方案要求您更改配置(即:使用另一个组件来模拟银行业务集成,或执行性能负载),则可以轻松处理(这确实可以配置DI端的优势)虽然IoC.
此外,如果您的应用程序在多个站点(具有不同的服务器和组件配置)中使用,或者在实时环境中具有更改的配置,则可以使用后续测试阶段来验证应用程序是否将处理这些更改.
生产
作为开发人员,您不会(也不应该)控制生产环境(特别是当您的应用程序分发给多个客户或单独的站点时),这对我来说是使用IoC和外部配置的真正好处因为它需要基础设施/生产支持来调整和调整实时环境,而不必返回开发人员并通过测试(当他们想要做的就是移动组件时成本更高).
摘要
IoC的外部配置的主要好处来自于为其他人(非开发人员)提供配置应用程序的能力,根据我的经验,这仅在有限的情况下有用:
应用程序分发到环境不同的多个站点/客户端.
在生产环境和设置上进行有限的开发控制/输入.
测试场景.
在实践中,我发现即使在开发可以控制环境的东西时它也会被运行,随着时间的推移,最好给别人更改配置的能力:
开发时你不知道什么时候会改变(应用程序是如此有用,你的公司将它出售给其他人).
我不想在每次请求稍微更改时更改代码,而这些更改可以通过设置和使用良好的配置模型来处理.
注意:应用程序是指完整的解决方案(不仅仅是可执行文件),因此应用程序运行所需的所有文件.
依赖注入是一种编码风格,其根源在于观察对象委托通常是比对象继承更有用的设计模式(即,对象具有 - 关系比对象更有用 - 关系).然而,对于DI来说,另一个成分是必要的,即创建对象接口.结合这两种强大的设计模式,软件工程师很快意识到他们可以创建灵活的松散耦合代码,从而诞生了依赖注入的概念.然而,直到对象反射在某些高级语言中才能实现,DI才真正起飞.反射组件是今天大部分时间的核心
语言必须为正常的面向对象编程技术以及对对象接口和对象反射(例如Java和C#)的支持提供良好的支持.虽然您可以在C++系统中使用DI模式构建程序,但在语言中缺乏反射支持可以防止它支持应用程序服务器和其他DI平台,从而限制了DI模式的表现力.
使用DI模式构建的系统的优势:
DI代码更容易重用,因为"依赖"功能被外推到定义良好的接口中,允许其配置由合适的应用程序平台处理的独立对象随意插入其他对象.
DI代码更容易测试.通过构建实现应用程序逻辑所期望的接口的"模拟"对象,可以在黑盒子中测试对象表示的功能.
DI代码更灵活.它是天生松散耦合的代码 - 极端.这允许程序员基于一端所需的接口和另一端的表达接口来选择对象的连接方式.
DI对象的外部(Xml)配置意味着其他人可以在不可预见的方向上自定义您的代码.
外部配置也是一种关注模式的分离,因为对象初始化和对象相互依赖性管理的所有问题都可以由应用服务器处理.
请注意,使用DI模式不需要外部配置,对于简单的互连,小型构建器对象通常就足够了.两者之间存在灵活性的权衡.构建器对象不像外部可见配置文件那样灵活.DI系统的开发人员必须权衡灵活性优于方便性的优点,注意在配置文件中表达的对物体构造的小规模细粒度控制可能会增加混乱和维护成本.
绝对的DI代码似乎更麻烦,让所有那些配置对象注入其他对象的XML文件的缺点看起来很困难.然而,这是DI系统的要点.您将代码对象混合和匹配作为一系列配置设置的能力允许您使用第三方代码构建复杂系统,而您只需要最少的编码.
问题中提供的示例仅仅涉及正确分解的DI对象库可以提供的表达能力的表面.通过一些练习和大量的自律,大多数DI从业者发现他们可以构建具有100%应用程序代码测试覆盖率的系统.仅这一点就是非同寻常的.这不是对几百行代码的小应用程序的100%测试覆盖率,而是包含数十万行代码的应用程序的100%测试覆盖率.我无法描述提供此级别可测试性的任何其他设计模式.
你是正确的,只有几行代码的应用程序比几个对象加上一系列XML配置文件更容易理解.但是,与大多数强大的设计模式一样,当您继续向系统添加新功能时,会发现增益.
简而言之,基于DI的大规模应用程序更易于调试且更易于理解.虽然Xml配置不是"编译时检查",但是如果作者试图将具有不兼容接口的对象注入另一个对象,则该作者知道的所有应用程序服务将向开发人员提供错误消息.大多数都提供"检查"功能,涵盖所有已知对象配置.通过检查要注入的对象A是否为所有已配置的对象注入实现对象B所需的接口,可以轻松快速地完成此操作.
这是一个有点问题,但我倾向于同意大量的xml配置并没有真正带来太大的好处.我喜欢我的应用程序尽可能轻松地依赖于依赖关系,包括大量的框架.
他们很多时候都会简化代码,但是它们也有复杂的开销,这使得追踪问题变得相当困难(我亲眼看到了这些问题,而直接的Java我会更舒服地处理).
我想这取决于风格,以及你感到满意的......你喜欢自己动手解决方案,并且有利于了解它,或者在现有解决方案的基础上,当配置不是很困难时对吗?这都是一种权衡.
但是,XML配置对我来说有点令人讨厌...我试图不惜一切代价避免它.
只要您将代码更改为数据,就可以朝着正确的方向迈出一步.
将任何内容编码为数据意味着您的代码本身更通用且可重用.它还意味着您的数据可以使用完全符合它的语言指定.
此外,XML文件可以读入GUI或其他工具,并且可以通过实际操作轻松操作.你会如何使用代码示例?
我一直在考虑大多数人将代码转化为数据的事情,它使得代码更加清晰.我发现人们不可能在代码而不是数据中创建一个菜单 - 显而易见的是,由于样板文件,在代码中进行操作是完全错误的.