依赖注入框架:它们如何工作?

时间:2010-10-19 23:57:13

标签: frameworks dependency-injection

我认为自己是一位经验丰富的程序员,并且理解依赖注入的基本概念。另一方面,我的大多数经验都是编写相对较低级别的单人数字运算代码。我没有任何从事大型企业项目的经验。

鉴于这种背景,我不能为我的生活包围我为什么有人需要一个框架来进行依赖注入。有人可以给我一个简短的概述这个框架是如何工作的,而不是涉及很多细节,并解释它如何使生活更轻松而不仅仅是滚动你自己?

编辑:我在这里得到了一些很棒的答案。我是否正确地说DI框架基本上为您提供了一种方便的方法来创建全局可访问的工厂,只要对象请求它们就会创建/返回依赖项实例?如果是这样,我一直在我的代码中以非常特殊的方式做这样的事情,但从未想过要使用任何形式的正式/重量级框架。

4 个答案:

答案 0 :(得分:7)

DI就是解耦类之间的依赖关系。

使用DI,您的类不再具有实现类的引用。工厂模式接近DI,但它是不同的,因为工厂类是自己的不必要的依赖(例如,这将伤害单元测试)。

DI也不一定是全球性或应用范围的;可以为同一个应用程序和相同的类配置不同的依赖关系模式。甚至可以存在运行时依赖性。 DI甚至可以确定对象需要生存的生命周期或范围(请求范围,会话范围等)。

如果你看一下像Google’s Guice这样的轻量级DI实现,它也不是重量级或侵入性的。他们称之为新的“新”并非毫无意义。

答案 1 :(得分:5)

维基百科对福利和实施有很好的写作。

http://en.wikipedia.org/wiki/Inversion_of_control

我发现像Spring这样的IoC容器是有用的,因为它们所做的所有其他“东西”,如事务管理,以及它们提供的代码,如代码模板,测试基类等,这些都是非常有用的。此外,在Java世界中,我认为IoC是对Java EE标准的反应,许多开发人员发现它太笨重了。 IoC由Spring实现,它允许您设计POJO服务组件,在大多数情况下,我认为这比Java EE让人们跳过的箍更容易。

我很多,或者至少其中一些是心理手淫,在某种程度上,这意味着容器提供的IoC优势在大多数使用它们的项目中都没有得到充分利用。
“我们应该使用DI,因为我们将来能够轻松地交换我们DAO的实现,yippeeeeee” - 在我的经验中很少发生。人们使用它们是因为它们已成为标准,并且流行语恕我直言。我不是说这是坏事;只是标准软件的IoC部分并不是它们使用的真正原因。

答案 2 :(得分:4)

我真的很喜欢@hvgotcodes的答案,但是我认为id加了几点,因为我是DI / IoC的忠实粉丝。

我们使用DI,具有以下优势:

  1. <强>可测即可。我们通过接口对Repository(例如)编写单元测试。现在,对于集成测试,我们使用DI为我们的测试注入“真正的”存储库。但是单元测试怎么样?我们不想测试“真正的”存储库/数据库。所以我们使用DI来“注入”模拟存储库。其中很多都与界面的魔力有关(当然,您可以“硬编码”您的测试以在需要时使用假存储库。)

  2. 注射的中心点。 - AKA注册表。每个项目/模块都有一个注册表,我们可以在其中轻拂开/关组件。例如,在我们的测试项目中,当“某事”请求IRepository时,我们注入一个MockRepository。在我们的服务层项目中,当“某事物”请求IRepository时,我们注入一个EntityFrameworkRepository。

  3. 优秀范围管理。这取决于DI容器(我们使用StructureMap for .NET)。但是,在设置注册表时,可以将对象设置为在单行中具有Singleton,HTTP-Context,ThreadLocal生存期。这又很好,因为你在中心位置处理对象。你的组件不知道他们的生命,他们可以专注于他们手头的工作,而不是其他任何事情。

  4. 单行切换组件。这可以通过注册表实现(第2点)。但目前我们正在使用Entity Framework进行持久化。唯一“知道”的是注册表。因此,如果有一天出现更好的事情,我们需要做的就是创建另一个IRepository实现,并在Registry中轻弹一行。这在长寿命应用中非常有用。我们使用L2SQL作为我们网站的v1,现在我们使用EF for v2。如果我们将DI与v1一起使用,那么切换时间几乎会减半。但是一切都与持久层有关,所以我们基本上是从头开始重写网站。

  5. 当您结合使用许多不同的原则(例如Repository,POCO,DDD,Interfaces,N-Tier)时,DI / IoC的好处真的很明显。

    我不会将它用于不太可能发展的小型应用程序。

    那是我的两分钱。

答案 3 :(得分:2)

如果你从DI路线开始,你很快就会有限制器,它为对象需要的各种依赖关系提供20个参数。获得这20个参数将需要获得20个其他参数来构建它们。然后,在这一切的最后(开始?),您将意识到您只是将自己与您仔细考虑的接口的具体实现相结合(通过调用构造函数)。然后,6个月后,您将添加一个新的依赖项,这需要您回溯所有现有的调用并更改它们。

DI框架基本上可以为您提供管道。通过站在你和构造函数之间,它可以查询配置(可能是XML,可能是代码),告诉它在需要具体对象时该做什么。

任何具有某种内省的语言都很容易使用基础知识(注册具体类型以满足接口,当需要接口实例然后实例化类型时。按照构造函数创建的图形并重复。 )当它变得复杂的时候想要控制对象的生命周期(这个Logger类只应该实例化一次,然后重用。这个DataAccessFacade应该每个线程实例化一次等)或动态选择如何满足依赖。 DI框架通常会提供对象创建工具(找出构造函数所需的依赖关系)以及Service Locator工具,这样就不必将所有内容都传递给构造函数或作为方法的参数。这允许您使用任意复杂的构造函数注册类型,获取它的实例,而不必担心何时或如何共享实例,何时构造,何时销毁,或者与实际类型耦合。

使用DI设计库还允许用户在需要时交换依赖关系 - 这在与接口或继承结合时提供了很大的灵活性,而不会因为每个依赖关系的构造函数或方法参数而使代码混乱。