什么时候使用依赖注入?

时间:2020-03-05 18:43:23  来源:igfitidea点击:

我最近一直在使用StructureMap,并且已经很享受了。但是,我可以看到如何轻松地将所有接口连接起来并最终得到将大量接口纳入其构造函数的类。即使在使用依赖项注入框架时这并不是一个大问题,但仍然感觉到某些属性确实不需要为了接口它们而需要接口。

与仅在类中添加属性相比,我们在哪里划界线?

解决方案

回答

"仅向类添加属性"是什么意思?

我的经验法则是使类单元可测试。如果类依赖于另一个类的实现细节,则需要对其进行重构/抽象,以便可以单独测试这些类。

编辑:我们提到了构造函数中的一系列接口。我建议改用setters / getters。我发现从长远来看,它使事情变得更容易维护。

回答

只有在有助于分离关注点时,我才这样做。

像跨项目一样,我将为我的一个图书馆项目中的实施者提供一个接口,实施项目将注入他们想要的任何特定实施。

就是这样...在所有其他情况下,这只会使系统变得不必要地复杂

回答

考虑一下设计。 DI允许我们通过配置更改来更改代码的功能。它还允许我们打破类之间的依赖关系,以便可以更轻松地隔离和测试对象。我们必须确定在哪里有意义,在哪里没有意义。没有轻拍的答案。

一个好的经验法则是,如果它太难测试了,那么我们将遇到单一责任和静态依赖项的一些问题。将执行单个功能的代码隔离到类中,并通过提取接口并使用DI框架在运行时注入正确的实例来打破该静态依赖关系。通过这样做,我们可以轻松地分别测试两个部分。

回答

即使拥有世界上的所有事实和程序,每个决定都归结为一个判断电话,忘记了,我在那读到
我认为这更像是一次体验/飞行时间的电话。
基本上,如果我们将依赖项视为可以在不久的将来替换的候选对象,请使用依赖项注入。如果我将" classA及其依赖项"视为一个替换块,那么我可能不会将DI用于A的部门。

回答

最大的好处是它将了解甚至发现应用程序的体系结构。我们将非常清楚地看到依赖链的工作方式,并且可以对单个部分进行更改,而无需更改不相关的内容。我们最终将得到一个松耦合的应用程序。这将推动我们进入更好的设计,并且当我们继续进行改进时会感到惊讶,因为设计将继续分离和组织代码。它也可以促进单元测试,因为我们现在有了一种自然的方式来替代特定接口的实现。

有些应用程序只是一堆东西,但是如果有疑问,我会继续创建接口。经过一些练习后,负担不大。

回答

我要解决的另一个问题是我应该在哪里使用依赖项注入?我们如何看待对StructureMap的依赖?仅在启动应用程序中?这是否意味着所有实现都必须从最顶层一直传递到最底层?

回答

依赖项注入的主要问题是,尽管它给出了松散耦合的体系结构的外观,但实际上却没有。

我们真正在做的是将这种耦合从编译时转移到运行时,但是,即使类A需要某个接口B才能工作,仍然需要提供实现接口B的类的实例。

依赖注入只应用于需要动态更改的应用程序部分,而无需重新编译基本代码。

我认为对反转控制模式有用的用法:

  • 插件架构。因此,通过选择正确的切入点,我们可以定义必须提供的服务的合同。
  • 类似于工作流的体系结构。我们可以在其中连接多个组件,将一个组件的输出动态连接到另一个组件的输入。
  • 每客户端应用程序。假设我们有多个客户,他们为项目的一组"功能"付费。通过使用依赖项注入,我们可以轻松地仅提供核心组件和一些"添加"组件,这些组件仅提供客户端已付费的功能。
  • 翻译。尽管通常不会出于翻译目的执行此操作,但是我们可以根据应用程序的需要"注入"不同的语言文件。根据需要包括RTL或者LTR用户界面。

回答

Dependency injection should only be used for the parts of the
  application that need to be changed dynamically without recompiling
  the base code

DI应该用于将代码与外部资源(数据库,Web服务,xml文件,插件体系结构)隔离。如果我们要测试依赖于数据库的组件,那么在许多公司中,测试代码中的逻辑所花费的时间几乎是禁止的。

在大多数应用程序中,数据库不会动态更改(尽管可以更改),但总的来说,不将应用程序绑定到特定的外部资源几乎总是一个好习惯。更改资源所涉及的数量应该很少(数据访问类的循环复杂度应该很少高于其方法之一)。

回答

我使用Castle Windsor / Microkernel,没有其他经验,但我非常喜欢。

至于我们如何决定注射什么?到目前为止,以下经验法则对我非常有用:如果该类非常简单,不需要单元测试,则可以随意在类中实例化它,否则我们可能希望通过构造函数具有依赖关系。

至于我们是否应该创建一个接口,而不仅仅是将方法和属性虚拟化,我认为如果我们a)可以看到该类在不同的应用程序(例如,记录器)中具有某种程度的可重用性,那么我们应该走接口路线),或者是由于构造函数参数的数量或者构造函数中存在大量逻辑的原因,否则很难模拟该类。