代码之家  ›  专栏  ›  技术社区  ›  dsimcha

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

  •  14
  • dsimcha  · 技术社区  · 14 年前

    我认为自己是一个经验丰富的程序员,并且了解依赖注入的基本概念。另一方面,我的大部分经验是编写相对低级的一人数字处理代码。我在大型企业项目方面毫无经验。

    考虑到这个背景,我不能一辈子都在思考为什么任何人都需要一个框架来进行依赖注入。有人能给我一个简单的概述,这样一个框架是如何工作的,而不涉及很多细节,并解释它是如何使生活比仅仅滚动你自己的简单?

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

    4 回复  |  直到 10 年前
        1
  •  7
  •   Menachem    10 年前

    DI主要是将类之间的依赖关系解耦。

    使用DI,类不再具有对实现类的引用。工厂模式接近于DI,但它的不同之处在于工厂类本身具有不需要的依赖性(例如,这将损害单元测试)。

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

    如果您查看轻量级DI实现(如 Google’s Guice . 他们称之为新的,并不是没有意义的。

        2
  •  5
  •   Arjan Tijms Mike Van    12 年前

    维基百科有一个很好的关于好处和实现的报道。

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

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

    在某种程度上,我很多,或者至少有些,是精神自慰,这意味着容器提供的IOC优势在大多数使用它们的项目中没有被充分利用。
    “我们应该使用DI,因为将来我们可以很容易地交换DAO的实现,Yippeeeee”——在我的经验中很少发生这种情况。人们使用它们是因为它们已经成为了一个标准,并且是一个时髦的词imho。我不是说这是坏事,只是标准软件的IOC部分并不是它们被使用的真正原因。

        3
  •  3
  •   RPM1984    14 年前

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

    我们使用DI有以下优点:

    1. 可测试性 . 我们通过接口针对存储库(例如)编写单元测试。现在,对于集成测试,我们使用DI为我们的测试注入一个“真正的”存储库。但是单元测试呢?我们不想测试“真实”的存储库/数据库。所以我们使用DI“注入”一个模拟存储库。其中很大一部分与接口的魔力有关(当然,您可以在需要时“硬编码”您的测试以使用假存储库)。

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

    3. 出色的范围管理 . 这取决于DI容器(我们将structuremap用于.NET)。但是,在设置注册表时,可以将对象设置为在一行中具有singleton、http上下文和threadlocal生存时间。这又是一个很好的方法,因为您在一个中心位置处理对象。您的组件不知道它们的生命周期,它们可以专注于手头的工作,而无其他。

    4. 元件单线切换 . 这是由注册表(点2)实现的。但目前我们正在使用实体框架来实现持久性。唯一“知道”这一点的是注册中心。因此,如果有一天有更好的结果出现,我们需要做的就是创建IRepository的另一个实现,并在注册表中跳过一行。这在长寿命应用中是非常可能的。我们在网站的v1中使用了l2sql,现在我们在v2中使用ef。如果我们在v1中使用di,那么转换的时间几乎会减少一半。但是一切都与持久层有关,所以我们基本上是从头开始重写网站。

    当您结合了许多不同的原则(如存储库、POCO、DDD、接口、N层)时,DI/IOC的好处就可以真正看到。

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

    那是我的两分钱。

        4
  •  2
  •   Mark Brackett    14 年前

    如果您从DI路由开始,您很快就会有一个收缩器,它为对象需要的各种依赖项取20个参数。获取这20个参数需要获取20个其他参数来构造它们。然后,在结尾(开始?)最重要的是,您将认识到您只是将自己耦合到经过仔细考虑的接口的具体实现(通过调用构造函数)。然后,6个月后,您将添加一个新的依赖项,这要求您回溯所有现有的调用并更改它们。

    DI框架基本上为您处理管道。通过站在您和构造器之间,它可以询问配置(可能是XML,也可能是代码),当需要一个具体的对象时,配置会告诉它应该做什么。

    对于任何具有某种自省的语言(注册一个具体的类型以满足接口,当您需要接口的实例时,然后实例化该类型),基础知识都非常简单。浏览由构造函数创建的图,然后重复。)它变得复杂的地方是 想要控制对象生命周期(这个记录器类应该只实例化一次,然后重用。这个dataAccessFacade应该每个线程实例化一次,等等),或者动态地选择如何满足依赖关系。DI框架通常提供对象创建工具(找出构造函数所需的依赖项)和服务定位器工具,以便并非所有内容都必须在构造函数中传递或作为方法的参数传递。它允许您用任意复杂的构造函数注册类型,获取类型的实例,而不必担心何时或如何共享实例,何时构造实例,何时销毁实例,或如何与实际类型耦合。

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