2011-10-06 105 views
3

我理解依赖注入,但没有那个“啊”的时刻,点击它,我真的看到了光。嘲笑的问题和依赖注入

我为什么要用DI?另外,当嘲讽那些使用文件系统的对象时,模拟对象能够做什么?它只是做虚拟调用(所以不真的使用文件系统)?

回答

1

让我去一对夫妇从hvgotcodesanswer几步远:

class Service { 
    Collaborator c = new Collaborator() 
} 

是你原来的班用硬编码的依赖性。

class Service { 
    Collaborator c; 

    Service(Collaborator c) { 
     this.c = c; 
    } 
} 

是你的注入依赖的新类。

到目前为止,这么好。现在,让我们取Collaborator并从中提取一个接口;称它为ICollaborator。现在你的新玩家看起来像这样:

class Service { 
    ICollaborator c; 

    Service(ICollaborator c) { 
     this.c = c; 
    } 
} 

这是什么给你买的?那么,你可以在你的代码,创建该类的行为像第一个例子是这样的:

// w00t! My code compiles and works again! Ship it! 
Service myService = new Service(new Collaborator()); 

漂亮添油加醋容易。当你想要使用不同类型的Collaborator时,美丽来自于 - 也许甚至是模拟或假的。只要它实现了接口ICollaborator,你就是金:

// I'm using Fake It Easy for this example. 
Service myService = new Service(A.Fake<ICollaborator>()); 

瞧!你现在有一个单元可测试的Service实例,它不会拖拽混凝土Collaborator(这将打破真正的“单元”测试)。

+0

我明白了。我明白,这是一个类似日期时间的好处。如果datetime从一个接口派生,并且我从同一个接口创建另一个类,那么这些方法可以是空的存根吗? – dotnetdev

+0

准确!现在,任何具有返回类型的方法都应该为该方法返回合理的值,但void方法可以是完全空的存根。 –

1

依赖注入只是一种不硬编码依赖到组件的做法。例如,

class Service { 
    Collaborator c = new Collaborator() 
} 

该伪码具有合作者硬编码。这很难改变。如果你没有

class Service { 
    Collaborator c; 

    Service(Collaborator c) { 
     this.c = c; 
    } 
} 

现在你可以通过构造函数'注入'所需的协作者到服务组件中。没有硬编码的依赖关系。

这很好,您可以轻松地更换协作者的实现。您的代码现在“松散耦合” - 对特定实现没有硬性依赖关系,仅限于类型和行为。

这样做的一个应用是,您现在可以在测试中注入一个模拟协作器来测试Service,这样您就可以以不依赖协作者的方式测试所有服务功能。

实际上,您希望Collaborator成为一个接口(或任何与您的选择语言支持相当的接口),以便您可以定义行为并将实现留给您注入的实际实例。

问题的第二部分,关于嘲笑执行文件操作的协作者是正确的。如果您嘲笑文件系统协作者,则可以单独测试使用协作者而不实际击中文件系统的内容

2

DI的目的是使代码松散耦合。根据定义,松散耦合需要单元测试,因为如果许多类紧密耦合,它不再是单元测试(而是集成测试)。

但是,DI的目的不是为了启用单元测试,而是为了让您的代码库更易于维护。许多积极的副作用之一是它也变得非常可测试。

当谈到嘲讽文件系统,它基本上是一个坏主意,文件系统等方面过于紧密镜子,因为这将导致Leaky Abstraction。相反,你应该考虑使用流或类似的概念。

0

要添加更多的讨论......

很多时候人们谈论DI的主要论点将沿着可测性的线条,但正如马克·西曼指出的(顺便说一下买他的书的时候关于DI,非常有启发性,对广告抱歉)最重要的方面是让你的应用程序松耦合,因此更易于维护。

要提供一个例子,在其他的答案中相同的代码:

比方说,你得到的是,根据新的要求....我不知道....一年的时间,你需要使用不同的合作者,你可以这样做以下:

ICollaborator collaborator; 

switch(timeOfYear) 
{ 
    case "Spring": 
     collaborator = new SpringCollaborator(); 
     break; 
    case "Summer": 
     collaborator = new SummerCollaborator(); 
     break; 
    case "Fall": 
     collaborator = new FallCollaborator(); 
     break; 
    case "Winter": 
     collaborator = new WinterCollaborator(); 
     break; 
} 

Service myService = new Service(collaborator); 

这种方式,因为你需要和你的服务将永远不需要改变,因为它不关心你可以创建许多实现只要它实现ICollaborator接口,协作者的详细信息。

有很多关于DI的更多信息,但松耦合和可测性始终是首先指出的两个好处。

问候。