何时使用dependency injection

在过去的几天中,我有一种特定的感觉,那就是dependency injection应该被称为“我无法下定决心” – 模式。 我知道这可能听起来很愚蠢,但实际上这是关于为什么我应该使用dependency injection(DI)的原因。 通常情况下,我应该使用DI来实现更高级别的松耦合,并且我会得到这个部分。 但真的…一旦我的select已经落在MS SQL或MySQL上,我多久才能更改一次数据库。很less有正确的?

有没有人有一些非常有说服力的理由为什么DI是要走的路?

两个单词, unit testing

DI最引人注目的原因之一是允许更简单的unit testing,而无需打开数据库,也不用担心设置“testing”数据。

DI对于解耦您的系统非常有用。 如果你所使用的是将数据库实现与应用程序的其余部分分开,那么你的应用程序非常简单,或者你需要对问题域进行更多的分析,发现问题域中的组件是最有可能发生变化的部分以及系统中具有大量耦合的组件。

当您针对代码重用,多function性和对问题域更改的稳健性时,DI是最有用的。

与项目的相关程度取决于代码的预期寿命。 根据工作types,您正在从一个项目到下一个项目进行零重用,因为大部分您正在编写的代码实际上可以接受。

使用DI的一个例子是创build一个应用程序,可以使用DI为客户端部署多个客户端,为客户端注入定制,这也可以被描述为GOF策略模式。 许多GOF模式可以通过使用DI框架来促进。

DI与企业应用程序开发更为相关,在这种开发中,您拥有大量的代码,复杂的业务需求以及系统将维护多年或数十年的期望(或希望)。

即使您在开发阶段不改变程序的结构,也会发现需要从程序的不同部分访问多个子系统。 使用DI,您的每个class级只需要提供服务,而且您无需手动提供所有布线。

这真的帮助我把注意力集中在软件devise中的事物交互上,而不是“谁需要随身携带,因为别人以后需要它”。

另外它还节省了大量的编写样板代码的工作。 我需要单身吗? 我只是configuration一个类是一个。 我可以用这样的“单身”来testing吗? 是的,我仍然可以(因为我只是configuration它只存在一次,但testing可以实例化一个替代实现)。

但是,在我使用DI之前,我并没有真正理解它的价值,但是尝试它让我大开眼界:我的devise比以前更加面向对象。 顺便说一下,在目前的应用程序,我不会unit testing(坏,坏我),但我仍然无法与DI生活在一起。 让事情变得更容易,保持课堂小而简单。

虽然我对数据库示例表示赞同,但是我发现使用DI很有帮助的一件大事是帮助我testing在数据库之上构build的图层。

这是一个例子…

你有你的数据库。

你有你的代码访问数据库并返回对象

你有业务领域的对象,采取以前的项目的对象,并与他们做一些逻辑。

如果将数据访问与业务领域逻辑合并,您的域对象可能变得难以testing。 DI允许您将自己的数据访问对象注入到您的域中,以便您不依赖于数据库进行testing或可能的演示(运行一个演示,其中一些数据是从xml而不是数据库中提取的)。

抽象这样的第三方组件和框架也将帮助你。

除了testing示例,还有一些地方可以通过合同devise方法使用DI。 你可能会发现创build一个处理引擎来调用你注入的对象的方法是合适的。 虽然它可能并不真正“处理它”,但它运行的方法在您提供的每个对象中都有不同的实现。

我看到了一个例子,其中每个业务域对象都有一个“保存”函数,在被注入处理器之后被调用。 处理器用configuration信息修改了组件,Save处理了对象的主要状态。 实质上,DI补充了符合接口的对象的多态方法实现。

dependency injection使您能够独立地testing特定的代码单元。

假设我有一个Foo类,例如在构造函数中需要一个类Bar的实例。 Foo上的其中一个方法可能会检查Bar的Property属性是否允许Bar其他处理发生。

 public class Foo { private Bar _bar; public Foo(Bar bar) { _bar = bar; } public bool IsPropertyOfBarValid() { return _bar.SomeProperty == PropertyEnum.ValidProperty; } } 

现在让我们来说Bar是实例化的,并且它的构造函数中的属性被设置为来自某个数据源的数据。 我该如何去testingFooIsPropertyOfBarValid()方法(忽略这是一个令人难以置信的简单例子)? 那么, Foo依赖于传递给构造函数的Bar的实例,而实例又依赖于来自属性设置的数据源的数据。 我们想要做的是将Foo从它所依赖的资源中分离出来,以便我们可以孤立地进行testing

这就是dependency injection的地方。我们想要的是有一些方法来伪造一个传递给FooBar实例,这样我们就可以控制在这个假Bar上设置的属性,并实现我们设置的目的,testing实现的IsPropertyOfBarValid()做我们希望它做的事情,即返回时Bar.SomeProperty == PropertyEnum.ValidProperty和false为任何其他值。

有两种types的假物体,Mocks和Stubs。 存根为被testing的应用程序提供input,以便testing可以在别的东西上执行。 另一方面嘲讽为testing提供input决定通过\失败。

Martin Fowler有关于Mock和Stubs之间区别的很好的文章

除了松耦合以外,任何types的testing都可以通过DI更加方便地进行。 你可以用一个模拟,一个虚拟甚至另一个版本replace一个被testing类的现有依赖。 如果一个类是直接实例化的,那么通常很难甚至不可能根据需要对它们进行“存根”操作。

我认为,当你有许多服务/组件,其实现必须在运行时根据外部configuration进行select时,值得使用DI。 (请注意,这样的configuration可以采用XML文件或代码注释和单独类的组合forms;select更方便的forms)。

否则,我会简单地使用一个ServiceLocator,它比整个DI框架“更轻”,更容易理解。

对于unit testing,我更喜欢使用模拟API来模拟对象,而不是要求它们从testing中被“注入”testing单元。 对于Java,一个这样的库是我自己的, JMockit 。

我今晚才明白。 对我来说,dependency injection是一种实例化对象的方法,需要大量的参数才能在特定的上下文中工作。

什么时候应该使用依赖注射? 你可以使用dependency injection,如果你以静态方式instanciate对象。 例如,如果您使用可以将对象转换为XML文件或JSON文件的类,并且只需要XML文件。 如果你不使用dependency injection,你将不得不instanciate对象和configuration很多东西。

什么时候你不应该使用depondancy注射? 如果一个对象与请求参数(在提交表单之后)联系在一起,你不应该使用depandancy注入,因为这个对象不是以静态方式实例化的。