Dependency injection 何时使用依赖项注入

Dependency injection 何时使用依赖项注入,dependency-injection,Dependency Injection,这几天我有一种感觉,依赖注入真的应该被称为“我拿不定主意”模式。我知道这听起来很傻,但实际上这是关于为什么我应该使用依赖注入(DI)的原因。经常有人说我应该使用DI来实现更高级别的松耦合,我得到了这一部分。但是真的。。。一旦我选择了MS SQL或MySQL,我多久更改一次数据库。。很少吧 有没有人有一些非常令人信服的理由来解释为什么DI是一条发展之路?两个字,单元测试 DI最令人信服的原因之一是允许更简单的单元测试,而无需访问数据库和担心设置“测试”数据。除了松耦合之外,任何类型的测试都可以通过

这几天我有一种感觉,依赖注入真的应该被称为“我拿不定主意”模式。我知道这听起来很傻,但实际上这是关于为什么我应该使用依赖注入(DI)的原因。经常有人说我应该使用DI来实现更高级别的松耦合,我得到了这一部分。但是真的。。。一旦我选择了MS SQL或MySQL,我多久更改一次数据库。。很少吧

有没有人有一些非常令人信服的理由来解释为什么DI是一条发展之路?

两个字,单元测试


DI最令人信服的原因之一是允许更简单的单元测试,而无需访问数据库和担心设置“测试”数据。

除了松耦合之外,任何类型的测试都可以通过DI轻松实现。您可以将测试中类的现有依赖项替换为mock、dummy甚至其他版本。如果一个类是在其依赖项被直接实例化的情况下创建的,那么如果需要的话,很难甚至不可能将它们“剔除”

虽然我半同意您对DB示例的看法,但我发现使用DI有助于我测试在数据库之上构建的层

这里有一个例子

你有你的数据库

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

您拥有业务域对象,这些对象接受上一个项目的对象并对它们执行一些逻辑

如果将数据访问与业务域逻辑合并,域对象可能会变得难以测试。DI允许您将自己的数据访问对象注入域中,这样您就不必依赖数据库进行测试或可能的演示(运行了一个演示,其中一些数据是从xml而不是数据库中拉入的)

像这样抽象第三方组件和框架也会对您有所帮助

除了测试示例之外,还有一些地方可以通过契约式设计方法使用DI。您可能会发现创建一个处理引擎是合适的,它可以调用您注入到其中的对象的方法。虽然它可能不是真正的“处理它”,但它运行的方法在您提供的每个对象中都有不同的实现


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

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

这确实有助于我将注意力集中在软件设计中事物的交互上,而不是“谁需要随身携带什么,因为别人以后需要它”

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

但是,顺便说一句,在我使用DI之前,我并不真正理解它的价值,但是尝试它对我来说是一个真正的大开眼界:我的设计和以前一样,更加面向对象。
顺便说一句,对于当前的应用程序,我不再进行单元测试(糟糕,糟糕的我),但我仍然无法再使用DI。移动对象和保持类的小而简单非常容易。

依赖项注入使您能够单独测试特定的代码单元

例如,假设我有一个类
Foo
,它在其构造函数中获取一个类
Bar
的实例。
Foo
上的方法之一可能会检查
Bar
的属性值是否允许对
Bar
进行其他处理

public class Foo
{
    private Bar _bar;

    public Foo(Bar bar)
    {
        _bar = bar;
    }

    public bool IsPropertyOfBarValid()
    {
        return _bar.SomeProperty == PropertyEnum.ValidProperty;
    }
}
现在让我们假设
Bar
被实例化,它的属性被设置为来自它的构造函数中某个数据源的数据。我该如何测试
Foo
IsPropertyOfBarValid()
方法(忽略这是一个非常简单的示例这一事实)?嗯,
Foo
依赖于传递给构造函数的
Bar
实例,后者又依赖于其属性设置为的数据源中的数据。我们想做的是用某种方法将
Foo
与它所依赖的资源隔离开来,这样我们就可以对它进行隔离测试

这就是依赖注入的用武之地。我们想要的是通过某种方式将
Bar
的实例伪传给
Foo
,这样我们就可以控制在这个伪
Bar
上设置的属性,并实现我们开始要做的,测试
IsPropertyOfBarValid()
的实现是否符合我们的预期,也就是说,当
Bar.SomeProperty==PropertyEnum.ValidProperty
时返回true,对于任何其他值返回false

有两种类型的伪对象,mock和stub。存根为被测试的应用程序提供输入,以便可以在其他对象上执行测试。另一方面,模拟为测试提供输入,以决定通过\失败


我认为,当您有许多服务/组件时,DI是值得使用的,这些服务/组件的实现必须在运行时根据外部配置进行选择。(请注意,这种配置可以采用XML文件的形式,也可以采用代码注释和单独类的组合形式;选择更方便的方式。)

否则,我只会使用