我的理解福利的依赖注射本身。让我们把弹簧的实例。我也明白的好处的其他弹featureslike 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();
}

如何可以IoC框架猜测其执行情况的myService我想要是注射如果有多一个吗?如果只有一个执行指定的接口,我让IoC容器自动决定使用它,它就会被打破后,第二次执行情况出现。如果没有意的只有一个可能的执行情况的一个接口,然后你不需要注入它。

这将是真的很有趣,看到小块的配置用于IoC其中显示了它的好处。我一直在使用弹簧时我不能提供这样的例子。我可以显示单个行证明好处的休眠、减少和其他框架,这是我的使用。


更新2:
我认识到,IoC配置是可以改变没有重新编译.这真的是这样一个好主意吗?我可以理解,当有人想要改变DB凭证,而无需重新编译-他可不是开发商。在实践中,如何经常有人还有其他比开发的变化IoC配置?我认为,对于开发商没有办法了重新编译,特别类,而不是改变配置。并非开发你可能会想让他的生活更容易并提供一些更简单的结构的文件。


更新3:

外部结构之间的映射的接口及其具体实现

有什么好在使它的体外?你不要使所有代码的外部,而你绝对可以的-只是把它放在ClassName.java.txt 文件阅读和编写手动飞-哇,你避免重新编译.为什么要汇编可避免的?!

你保存编码的时间,因为你提供的映射声明的方式,而不是在一个程序代码

我的理解是,有时候声明的方法,节省了时间。例如,我宣布仅一旦之间的映射豆酒店和一个数据库列和休眠使用这映,同时装、节约、建设SQL基于HSQL,等等。这是声明性方法工作。在情况下的弹(在我的例子),宣言有更多的线和有同样的表现为相对应的代码。如果有一个例子的时候这样的声明比较短的码-我要看到它。

反转的控制原则允许容易单元的测试因为你可以代替真正的实现与假的(如替换SQL数据库中存储器之一)

我不明白倒置的控制的好处(我喜欢叫的设计图案在这里讨论为依赖注射,因为IoC是更大-有很多种的控制,并且我们相只有一个他们控制的初始化)。我是问为什么有人都需要其他的东西比一种编程语言。我肯定可以代替真正的实现与假的使用代码。和这个代码表达同样的事情,如结构-它只是将初始化领域与假的价值观。

mary = new FakeFemale();

我不明白的好处。我不明白有什么好处是增加外部XML配置相比,配代码,不相同。我不认为,汇编应该避免的-我编的每一天,我仍然活着。我认为结构迪是坏的例的声明的做法。宣言可能是有用的,如果是宣布一次用多次在不同的方式似休眠在那里的映射之间的豆财产和数据库列用于保存、装载、建筑物的搜索查询,等等。弹簧迪配置可以很容易地翻译的配置代码,就像在开始的这个问题,可以吗?它仅用于豆初始化,不是吗?这意味着一个声明的做法并不增加任何东西在这里,不是吗?

当我宣布休眠映,我只是得休眠一些信息,以及它的工作的基础上它-我不告诉它该怎么做。在春季,我的宣言》告诉弹正是从做到-那么为什么它声明,为什么不做呢?


最后更新:
伙计们,很多答复都告诉我关于依赖注射我知道是好的。问题是有关目的DI配置,而不是初始代码-我倾向于认为,初始化码短和清晰。唯一的答案,我得到了迄今为止我的问题是,它避免了重新编译,当配置的变化。我想我应该员额的另一个问题,因为这是一个很大的秘密对我来说,为什么编纂应避免这种情况。

有帮助吗?

解决方案

为自己的主要原因之一使用一个IoC(和使用的外部结构)是围绕两个领域:

  • 测试
  • 生产的维护

测试

如果你分割你的测试成3的方案(这是相当正常的,在大规模发展):

  1. 单元的测试
  2. 集成测试
  3. 黑盒测试

你怎么会想要做的就是过去两个试验方案(集成和黑盒),没有重新编译的任何应用程序的一部分。

如果你的任何测试方案要求你改变结构(即:使用的另一个组件来模仿一个银行业务的整合,或者做一个绩效载荷),这可以很容易地处理(本不会在好处的配置迪一侧的IoC虽然。

此外,如果应用或者在多个站点(与不同服务和分配)或者有一个改变结构上的生活环境可以使用的后期阶段测试,以验证程序将处理这些变化。

生产

作为开发者,你不要(而不应)有控制的生产环境(特别是当你的程序是正在分发给多个客户或单独的站点),这对我来说是真正的好处,使用一个海洋学委员会和外部结构,因为它是基础设施/生产的支持调整和调整生活环境没有必要回到开发商和通过测试(高成本时,所有他们想要做的是移动的一个成分)。

摘要

主要福利的外部结构的一个IoC来从给予其他(非开发人员)的力量配置的应用程序,在我的经验这仅仅是有用的下一组有限的情况下:

  • 应用程序分发给多个网站的客户在环境将有所不同。
  • 有限的发展控制输入过生产环境和安装。
  • 测试方案。

在实践中我们发现,即使在发展的东西,你没有控制的环境中,它会上运行的,随着时间最好是得到别人的能力,以改变的配置:

  • 当发展中你不知道什么时候它会改变的(应用程序是很有用的公司出售给其他人).
  • 我不想被困与不断变化的代码,每次一个轻微的改变请求,可能已处理过建立和使用一个良好的配置模型。

注:应用程序是指完整的解决方案(而不只是可执行),因此,所有文件应用程序需要运行.

其他提示

依赖注入是一种编码风格,其根源在于观察对象委托通常是比对象继承更有用的设计模式(即,对象具有 - 关系比对象更有用 - 关系)。然而,对于DI来说,另一个成分是必要的,即创建对象接口。结合这两种强大的设计模式,软件工程师很快意识到他们可以创建灵活的松散耦合代码,从而诞生了依赖注入的概念。然而,直到DI确实起飞的某些高级语言中的对象反射才出现。反射组件是当今大多数DI系统的核心,因为DI的真正酷的方面需要能够以编程方式选择对象并使用外部系统配置并将其注入其他对象,并独立于对象本身。

语言必须为正常的面向对象编程技术以及对对象接口和对象反射(例如Java和C#)的支持提供良好的支持。虽然您可以在C ++系统中使用DI模式构建程序,但在语言中缺乏反射支持可以防止它支持应用程序服务器和其他DI平台,从而限制了DI模式的表现力。

使用DI模式构建的系统的优势:

  1. DI代码更容易重用,因为“依赖”功能被外推到定义良好的接口中,允许其配置由合适的应用程序平台处理的独立对象随意插入其他对象。
  2. DI代码更容易测试。通过构建实现应用程序逻辑所期望的接口的“模拟”对象,可以在黑盒子中测试对象表示的功能。
  3. DI代码更灵活。它是天生松散耦合的代码 - 极端。这允许程序员根据一端所需的接口和另一端的表达接口来选择对象的连接方式。
  4. DI对象的外部(Xml)配置意味着其他人可以在不可预见的方向上自定义您的代码。
  5. 外部配置也是一种关注模式的分离,因为应用服务器可以处理对象初始化和对象相互依赖性管理的所有问题。
  6. 请注意,使用DI模式不需要外部配置,对于简单的互连,小型构建器对象通常就足够了。两者之间存在灵活性的权衡。构建器对象不像外部可见配置文件那样灵活。 DI系统的开发人员必须权衡灵活性优于方便性的优点,注意在配置文件中表达的对物体构造的小规模,细粒度控制可能会增加混乱和维护成本。
  7. 绝对DI代码看起来更麻烦,让所有那些配置对象注入其他对象的XML文件的缺点看起来很困难。然而,这是DI系统的要点。您可以将代码对象混合和匹配为一系列配置设置,这样您就可以使用第三方代码构建复杂的系统,而且编码最少。

    问题中提供的示例仅涉及正确分解的DI对象库可以提供的表达能力的表面。通过一些练习和大量自律,大多数DI从业者发现他们可以构建具有100%应用程序代码测试覆盖率的系统。仅这一点就是非同寻常的。这不是对几百行代码的小应用程序的100%测试覆盖率,而是对ap的100%测试覆盖率

这是一个有点问题的问题,但我倾向于同意大量的xml配置并没有太大的好处。我喜欢我的应用程序尽可能地依赖于依赖关系,包括大量的框架。

他们很多时候都会简化代码,但是它们也有复杂的开销,这使得追踪问题变得相当困难(我亲眼看到了这些问题,直接的Java我会更舒服地处理)

我认为这取决于风格,以及你感到满意的......你喜欢自己动手解决方案,并且有利于内部了解它,或者在现有的解决方案上付出代价配置不正确吗?这都是一种权衡。

但是,XML配置对我来说有点小麻烦......我会不惜一切代价避免它。

只要您将代码更改为数据,就可以朝着正确的方向迈出一步。

将任何内容编码为数据意味着您的代码本身更通用且可重用。这也意味着您的数据可以用恰好适合它的语言指定。

此外,XML文件可以读入GUI或其他工具,并且可以通过实际操作轻松操作。你会如何使用代码示例?

我一直在考虑大多数人将代码转化为数据的事情,它使得代码更加清晰。我发现不可思议的是,人们会在代码而不是数据中创建一个菜单 - 很明显,由于样板文件,在代码中进行操作是完全错误的。

使用DI容器的原因是您不必在代码中预先配置十亿个属性,这些属性只是getter和setter。你真的想用新X()硬编码所有那些吗?当然,你可以有一个默认值,但DI容器允许创建非常简单的单例,并且可以让你专注于代码的细节,而不是初始化它的杂项任务。

例如,Spring允许您实现InitializingBean接口并添加afterPropertiesSet方法(您还可以指定“init-method”以避免将代码耦合到Spring)。这些方法将允许您确保在启动时正确配置了作为类实例中的字段指定的任何接口,然后您不再需要对getter和setter进行空值检查(假设您允许单例保持线程安全) )。

此外,使用DI容器进行复杂的初始化要轻松得多,而不是自己做。例如,我协助使用XFire(不是CeltiXFire,我们只使用Java 1.4)。该应用程序使用Spring,但遗憾的是它使用了XFire的services.xml配置机制。当一个元素集合需要声明它有ZERO或更多实例而不是一个或多个实例时,我不得不覆盖这个特定服务的一些提供的XFire代码。

在其Spring bean架构中定义了某些XFire默认值。因此,如果我们使用Spring来配置服务,则可以使用bean。相反,发生的事情是我必须在services.xml文件中提供特定类的实例,而不是使用bean。为此,我需要提供构造函数并设置在XFire配置中声明的引用。我需要做的真正改变需要我重载一个类。

但是,多亏了services.xml文件,我不得不创建四个新类,根据构造函数中Spring配置文件中的默认值设置它们的默认值。如果我们能够使用Spring配置,我可以说:

<bean id="base" parent="RootXFireBean">
    <property name="secondProperty" ref="secondBean" />
</bean>

<bean id="secondBean" parent="secondaryXFireBean">
    <property name="firstProperty" ref="thirdBean" />
</bean>

<bean id="thirdBean" parent="thirdXFireBean">
    <property name="secondProperty" ref="myNewBean" />
</bean>

<bean id="myNewBean" class="WowItsActuallyTheCodeThatChanged" />

相反,它看起来更像是这样:

public class TheFirstPointlessClass extends SomeXFireClass {
    public TheFirstPointlessClass() {
        setFirstProperty(new TheSecondPointlessClass());
        setSecondProperty(new TheThingThatWasHereBefore());
    }
}

public class TheSecondPointlessClass extends YetAnotherXFireClass {
    public TheSecondPointlessClass() {
        setFirstProperty(TheThirdPointlessClass());
    }
}

public class TheThirdPointlessClass extends GeeAnotherXFireClass {
    public TheThirdPointlessClass() {
        setFirstProperty(new AnotherThingThatWasHereBefore());
        setSecondProperty(new WowItsActuallyTheCodeThatChanged());
    }
}

public class WowItsActuallyTheCodeThatChanged extends TheXFireClassIActuallyCareAbout {
    public WowItsActuallyTheCodeThatChanged() {
    }

    public overrideTheMethod(Object[] arguments) {
        //Do overridden stuff
    }
}

因此最终结果是,必须在代码库中添加四个额外的,几乎没有意义的Java类,以实现一个额外的类和一些简单的依赖容器信息实现的影响。这不是“证明规则的例外”,这是规则......当DI容器中已经提供了属性并且您只需更改它们以适应特殊情况时,处理代码中的怪癖会更加清晰,这种情况经常发生。

我有你的答案

有明显的贸易平衡中的每一个方法,但是外部化的XML配置文件是有用的企业发展在建立系统的使用编码并不是你的IDE。使用建立系统,您可能想注入一定的价值进入你的代码-例如版本的建立(这可能是痛苦的,必须手动更新每次汇编).疼痛是更大的当你建立系统的拉代码的一些版本控制系统。修改简单的价值在编制时将会需要你改变一个文件提交、汇编,然后将恢复每次为每个变化。这些都不是改变,你想要承诺到您的版本控制。

其他有用的使用情况下关于建立系统和外部的配置:

  • 注射的样式/式表一个单一的编码基于不同的版本
  • 注套不同的动态内容(或引用他们)对于你的单码基
  • 注入的本地化背景不同的建立/客户
  • 改变一个服务URI到备份服务器(当时主要的一个下去)

更新:上述所有例子的事情,并不一定需要依赖关系课程。但你可以很容易地建立的情况下,既是一个复杂的对象和自动化是必要的,例如:

  • 想象一下,你有一个系统,在其它监控的交通网站。根据#并发用户,事实证明on/off记录机制。也许同时该机制是关闭的,有存根的对象是放在它的地方。
  • 想象一下,你有一个网络会议系统,其中根据不同的用户使用,你想换的能力做P2P根据不同的参与者

每次更改配置中的内容时,都无需重新编译代码。它将简化程序部署和维护。例如,只需在配置文件中进行一次更改,就可以将一个组件与另一个组件交换。

您可以为女朋友插入新的实施方案。因此可以在不重新编译代码的情况下注入新的女性。

<bean id="jane" class="foo.bar.HotFemale">
  <property name="age" value="19"/>
</bean>
<bean id="mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="john" class="foo.bar.Male">
  <property name="girlfriend" ref="jane"/>
</bean>

(以上假设Female和HotFemale实现相同的GirlfFriend界面)

在.NET世界中,大多数IoC框架都提供XML和代码配置。

例如,

StructureMap和Ninject使用流畅的接口来配置容器。您不再受限于使用XML配置文件。 Spring也存在于.NET中,它很大程度上依赖于XML文件,因为它是他历史上的主要配置界面,但仍然可以通过编程方式配置容器。

轻松将部分配置组合成最终的完整配置。

例如,在Web应用程序中,模型,视图和控制器通常在单独的配置文件中指定。使用声明方法,您可以加载,例如: <代码>

  UI-context.xml
  Model-context.xml
  Controller-context.xml

或者使用不同的UI和一些额外的控制器加载: <代码>

  AlternateUI-context.xml
  Model-context.xml
  Controller-context.xml
  ControllerAdditions-context.xml

在代码中执行相同操作需要用于组合部分配置的基础结构。在代码中并非不可能,但使用IoC框架肯定更容易。

通常,重要的一点是在编写程序后更改配置。通过代码中的配置,您隐含地假设更改它的人具有与原始作者相同的技能和对源代码的访问权限。

在生产系统中,将一些设置子集(例如,您的例子中的年龄)提取到XML文件并允许例如系统管理员或支持个人更改值而不给予他们对源代码或其他设置的全部权力 - 或者只是为了将它们与复杂性隔离开来。

从春天的角度来看,我可以给你两个答案。

首先,XML配置不是定义配置的唯一方法。大多数事情都可以使用注释进行配置,而必须使用XML完成的事情是对您不编写的代码的配置,例如您从库中使用的连接池。 Spring 3包含一种使用Java定义DI配置的方法,类似于示例中的手动DI配置。所以使用Spring并不意味着你必须使用基于XML的配置文件。

其次Spring不仅仅是一个DI框架。它还有许多其他功能,包括事务管理和AOP。 Spring XML配置将所有这些概念混合在一起。通常在同一个配置文件中,我指定了bean依赖项,事务设置和添加实际在后台使用AOP处理的会话范围bean。我发现XML配置提供了一个更好的地方来管理所有这些功能。我还认为基于注释的配置和XML配置比基于Java的配置更好地扩展。

但我确实看到了你的观点,在Java中定义依赖注入配置没有任何问题。我通常在单元测试中自己这样做,当我正在开展一个足够小的项目时,我还没有添加DI框架。我通常不会在Java中指定配置,因为对我而言,当我选择使用Spring时,我正试图摆脱写作的那种管道代码。但这是一个偏好,但这并不意味着XML配置优于基于Java的配置。

Spring也有一个属性加载器。我们使用此方法设置依赖于环境的变量(例如开发,测试,验收,生产......)。这可以是例如要收听的队列。

如果没有理由改变该属性,也没有理由以这种方式配置它。

你的情况非常简单,因此并不需要一个IoC(反转的控制)容器就像春天。另一方面,当"程序接口,没有实现"(这是一个很好的做法,在面向对象的),可以有这样的代码:

IService myService;
// ...
public void doSomething() {
  myService.fetchData();
}

(注意,这种类型的myService是IService--一个接口,没有一个具体实现)。现在它可以很方便让你IoC容器自动提供正确的具体实例IService期间初始化的-当你拥有许多接口和许多实现,它可能很麻烦,这样做。主要好处的一个IoC容(依赖注射框架):

  • 外部结构之间的映射的接口及其具体实现
  • IoC容器处理一些棘手的问题,解决复杂的依赖关系的图表管理组件的生命周期等等。
  • 你保存编码的时间,因为你提供的映射声明的方式,而不是在一个程序代码
  • 反转的控制原则允许容易单元的测试因为你可以代替真正的实现与假的(如替换SQL数据库中存储器之一)

在XML配置文件中初始化将简化您在其计算机上部署应用程序的客户端的调试/调整工作。 (因为它不需要重新编译+二进制文件替换)

其中一个最吸引人的原因是“好莱坞原则”:“don”打电话给我们,我们会打电话给你。组件不需要对其他组件和服务本身进行查找;相反,它们会自动提供给它。在Java中,这意味着不再需要在组件内部进行JNDI查找。

单独对组件进行单元测试也更容易:不是给它实际需要的组件实现,而是简单地使用(可能是自动生成的)模拟。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top