Dependency injection 模拟问题和依赖注入
我理解依赖注入,但还没有“啊”的那一刻,它点击了一下,我真的看到了曙光Dependency injection 模拟问题和依赖注入,dependency-injection,Dependency Injection,我理解依赖注入,但还没有“啊”的那一刻,它点击了一下,我真的看到了曙光 我为什么要使用DI?另外,当模拟使用文件系统的对象时,模拟对象能够做什么?它是否只是进行虚拟调用(因此并不真正使用文件系统)?依赖项注入只是不将依赖项硬编码到组件中的一种实践。比如说 class Service { Collaborator c = new Collaborator() } 该伪代码将协作者硬编码。很难改变。如果是的话 class Service { Collaborator c;
我为什么要使用DI?另外,当模拟使用文件系统的对象时,模拟对象能够做什么?它是否只是进行虚拟调用(因此并不真正使用文件系统)?依赖项注入只是不将依赖项硬编码到组件中的一种实践。比如说
class Service {
Collaborator c = new Collaborator()
}
该伪代码将协作者硬编码。很难改变。如果是的话
class Service {
Collaborator c;
Service(Collaborator c) {
this.c = c;
}
}
现在,您可以通过构造函数将所需的协作者“注入”到服务组件中。没有硬编码的依赖项
class Service {
Collaborator c;
Service(Collaborator c) {
this.c = c;
}
}
这很好,所以您可以轻松地交换协作器的实现。您的代码现在是“松散耦合的”——对特定实现没有硬依赖,只对类型和行为有硬依赖
这样做的一个应用是,您现在可以通过在测试中注入模拟协作者来测试服务
,这样您就可以以不依赖协作者的方式测试所有服务功能
实际上,您希望Collaborator
成为一个接口(或您选择的语言支持的任何等效接口),以便您可以定义行为,并将实现留给您注入的实际实例
问题的第二部分,关于模拟执行文件操作的协作者,是正确的。如果模拟文件系统协作器,则可以单独测试使用协作器的内容,而不会实际影响文件系统。DI的目的是使代码松散耦合。根据定义,单元测试需要松散耦合,因为如果许多类紧密耦合,那么它就不再是单元测试(而是集成测试) 然而,DI的目的不是支持单元测试,而是使您的代码库更易于维护。许多积极的副作用之一是,它也变得更容易测试
在模拟文件系统时,将文件系统的各个方面镜像得太近基本上是一个坏主意,因为这将导致。相反,你应该考虑使用流或类似的概念。
让我再向前走几步:
是具有硬编码依赖项的原始类class Service {
Collaborator c;
Service(Collaborator c) {
this.c = c;
}
}
是具有注入依赖项的新颖类
class Service {
Collaborator c;
Service(Collaborator c) {
this.c = c;
}
}
到目前为止,一切顺利。现在,让我们使用Collaborator
并从中提取一个接口;称之为ICollaborator。现在,您的newerfangled类如下所示:
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());
非常容易切割和干燥。当你想使用一种不同类型的合作者时,这种美就来了,甚至可能是一种模仿或伪造的合作者。只要它实现了ICollaborator
接口,您就是黄金:
// I'm using Fake It Easy for this example.
Service myService = new Service(A.Fake<ICollaborator>());
//我在这个例子中使用了Fake It Easy。
服务myService=新服务(A.Fake());
瞧!您现在有了一个可单元测试的服务
实例,它不会将具体的合作者
拖到一起(这将打破真正的“单元”测试)。为讨论添加更多内容
大多数时候,当人们谈论DI时,主要的论点都是关于可测试性的,但是正如Mark Seeman指出的(顺便说一句,买一本关于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还有很多,但松散耦合和可测试性始终是最先指出的两个优点
问候。我明白了。我知道这是datetime的一个优点。如果datetime派生自一个接口,并且我从同一接口创建了另一个类,那么这些方法可以是空存根吗?准确地说!现在,任何具有返回类型的方法都应该为该方法返回合理的内容,但是void方法可以是完全空的存根。