我理解依赖注入,但没有那个“啊”时刻,它点击的地方,我真的看到了光。
我为什么要使用DI?此外,当模拟像使用文件系统的对象时,模拟对象能够做什么?它是否只是进行虚拟调用(所以不真正使用文件系统)?
答案 0 :(得分:2)
DI的目的是使代码松散耦合。根据定义,单元测试需要松散耦合,因为如果许多类紧密耦合,则不再是单元测试(而是集成测试)。
但是,DI的目的不是为了启用单元测试,而是为了使代码库更易于维护。许多积极的副作用之一是它也显得更加可测试。
当涉及到模拟文件系统时,过于密切地镜像文件系统的各个方面基本上是一个坏主意,因为这将导致 Leaky Abstraction 。相反,您应该考虑使用流或类似的概念。
答案 1 :(得分:1)
依赖注入只是不依赖于编码组件的实践。例如
class Service {
Collaborator c = new Collaborator()
}
伪代码对协作者进行了硬编码。这很难改变。如果你做了
class Service {
Collaborator c;
Service(Collaborator c) {
this.c = c;
}
}
现在您可以通过构造函数将所需的协作者“注入”Service组件。没有硬编码的依赖。
这很好,因此您可以轻松地更换协作者的实现。您的代码现在“松散耦合” - 对特定实现没有硬性依赖,只有类型和行为。
这样做的一个应用是,您现在可以通过在测试中注入模拟协作者来测试Service
,这样您就可以以不依赖于协作者的方式测试所有服务功能。
实际上,您希望Collaborator
成为一个接口(或者您选择的语言支持的任何等价物),以便您可以定义行为,并将实现保留到您注入的实际实例。
关于模拟执行文件操作的协作者的问题的第二部分是正确的。如果您模拟文件系统协作者,则可以在不实际访问文件系统的情况下测试单独使用协作者的内容
答案 2 :(得分:1)
让我再远离hvgotcodes answer:
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
以进行骑行(这将打破真正的“单元”测试)。
答案 3 :(得分: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还有很多,但松耦合和可测试性总是首先指出的两个好处。
问候。