全局与依赖注入
本文关键字:注入 依赖 全局 | 更新日期: 2023-09-27 18:32:58
有人说最好使用依赖注入。为什么?
我认为最好是很少的全局、易于访问的类,而不是庞大的构造函数。
它是否以任何方式影响应用程序速度?
这两者的混合可能是最好的。
主要优点是解耦,这将有助于单元测试。这完全取决于您如何编写这些"易于访问的类"。
这个想法是这样的。类通过仅依赖于合约(interface
(来与实现(class
(依赖关系分离。在你的实时环境中,你可能永远不会提供一个新的实现类,但在你的测试环境中,你很可能会(无论是手工制作的存根,还是来自模拟框架的模拟类(。
应用程序速度需要分析,但使用 DI 框架可能会产生一些开销,而不是直接与您知道的单例对话。重要的问题是:这种开销是问题吗?只有性能预期和分析才能告诉您这一点。根据我的经验,好处远远超过可以忽略不计的性能损害。
使用static
类和方法作为全局变量。它们对性能没有任何影响。但是,静态类不适合可测试性。
静态方法的缺点是什么?
此外,一旦您的代码与静态类 (Globals( 紧密耦合,您将来将无法用备用实现替换它们。因此,除非在非常简单的情况下使用,否则全局可能不是好的设计。
请注意,静态类和方法是编译时绑定,而 DI 是运行时绑定。帮助您保持课程松散耦合。
使用"globals"和DI之间存在巨大差异。首先,路径通常不会出错,因为您可能会逐步通过单一实例和服务定位器。今天,两者都被认为是一种反模式。原因是我们应该设计可测试的代码,当我们需要更改代码库以进行维护或满足新要求时,这给了我们很大的优势。如果代码解耦,则很容易实现可测试性。正如你猜的那样,全局行为对解耦没有帮助,所以例如,如果你有代码加入一个静态单例,要测试这样的代码,你需要单例本身,你不能模拟它,这很糟糕,因为你不能随心所欲地给你的系统压力。乍一看,服务定位器似乎更好:如果需要测试,您可以模拟服务定位器,但您必须:
- 提前知道被测系统将向定位器询问哪些服务
- 始终创建一个"递归模拟",因为您可能也会模拟返回的服务。
构造函数上的 DI 是代码解耦的好方法,因为您可以非常清楚地说明对象需要运行什么,并且可以一目了然地决定要模拟的内容、存根等。请注意,DI 将起作用并帮助您,前提是您确保 DI 内核不会作为依赖项跨代码行走:这将在反模式中转换 DI(您将代码解耦,但将其绑定到容器(,所以请记住研究并真正实现组合根模式,这将真正帮助您编写更好和可测试的代码。
我认为关于这个主题的顶级文章对 DI 以及如何以正确的方式使用它有一个很好的总结: 依赖注入 (DI( "友好"库
如果你想更深入地研究这个话题,我可以推荐Mark Seeman的《.NET中的依赖注入》一书。