构造函数中的依赖注入容器

2023-12-08

为什么将容器放在构造函数中这么糟糕?例如,您想要在另一个类 (C) 的构造函数中解析类 B,因为您需要将类 (B) 与解析的依赖项一起使用(您开始按照您希望的方式使用类 C,就像使用 B 一样,但使用依赖关系已解决)。


为什么将容器放在构造函数中这么糟糕?

我想您的意思是将容器作为构造函数参数传递。这实际上是服务定位器模式的变体,在这种情况下被认为是反模式。您可能不想这样做有几个原因。

首先,类的用户只会知道该类需要一个容器来解决其依赖关系。这些信息量等于根本没有信息,因为你仍然不知道该类将依赖于什么。您想为班级编写单元测试吗?您必须查看类内部并查看它正在解析什么类型,模拟它们并为每个测试初始化​​容器。这也意味着对某些代码的更改将使其可以编译,但可能会破坏某些测试:例如,当新代码依赖于尚未在容器中注册的类时,就会出现这种情况。

使用服务定位器时常见的次要影响是,您永远无法确定在请求依赖项时不会在运行时遇到异常。每个班级都正确注册了吗?虽然某些容器提供了检查每个接口是否已注册的可能性,但这并不意味着它已注册到正确的类型。例如,可能会发生一个类型使用两个不同的实现注册两次的情况,并且很难注意到是否有任何代码片段可以调用容器。

对此的更好的解决方案是组成 根模式. 这篇博文还解释了为什么服务定位器可能不是一个好主意。


根据新的发展进行编辑:

显然您正在使用第三方库,它依赖于您的类具有默认构造函数。让我们假设您无法影响类的实例化,并且您必须让该框架完成其工作。请注意,这可能是一个很大的假设,请首先调查第三方库以了解执行此操作的可能性。乍一看,像 ASP.NET WebForms 和 WCF 这样的框架并没有给您太多机会,但有一些方法可以减轻这些情况的痛苦。

我的意思只是在构造函数中创建容器,添加 分别对容器的依赖并解析对象,其中 可以通过简单地创建依赖对象的实例来完成 用它来创建依赖对象。

我可能遗漏了一些东西,但是为什么需要在构造函数中注册依赖项?难道你不能只在构造函数中解析它,然后在其他地方注册它吗?那仍然是一个服务定位器,但你至少会做正确的错事。

为什么在构造函数中这样做是一个坏主意,而在其他地方这样做是一个坏主意 还好吗?

这样做anywhere但在一个地方是一个坏主意。为什么要将容器注册分散到各处?如果您确实觉得需要决定在运行时使用哪种接口实现,请使用类似工厂之类的东西。

那么,为什么不好呢?

  • 客户端类依赖于实现和接口,这并不比在构造函数中更新具体类更好。
  • 客户端类现在也依赖于容器,并且出现了服务定位器的问题(见上文),使得现在这种方法比更新具体类更糟糕。

正如@Steven 所说,您将失去依赖注入的所有优势。真正的根本问题是:为什么你绝对想在这个地方进行 DI?您想使用该方法的哪些优点?根据答案,可能有多种解决方案。我脑海中浮现出两个例子:

解决方案1:丢失第三方库实例化的类的 DI。

解决方案2:使用 Bastard Injection + Service Locator 的组合。在这种情况下,两个错误就可以构成一个正确。

public class MyClass
{
    public MyClass()
        : this(Container.Resolve<IDependency>())
    {
    }

    public MyClass(IDependency dep)
    {
    }
}

在这种情况下,您没有在构造函数中使用非本地依赖项,因为它是由服务定位器解析的,因此您对实现没有依赖项。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

构造函数中的依赖注入容器 的相关文章

随机推荐

  • 在 WinForms 线程上使用 CoInitializeEx

    我正在为 DSLR 相机开发一个 SDK 其中包含以下说明 开发Windows应用程序的注意事项 创建应用程序时 在 Windows 下运行的每个程序都需要 COM 初始化 线程以便从主线程以外的线程访问相机 线 创建用户线程并从中访问相机
  • 两个或多个带进度的前台通知在更新其进度时相互替换

    我有一项服务将在前台运行上传任务 然后在通知中显示进度 由于用户可能会使用不同的 id 请求多次上传 因此将运行两个或多个前台服务 一切正常 但我想要的是使用此代码显示所有任务的通知和进度 NotificationCompat Builde
  • 使用关联实体的正确方法是什么?

    这是描述 绘制 Poke Hospital 的实体关系图 其中提供 为神奇宝贝提供医疗服务 每个神奇宝贝都会与其中一位护士乔伊有个约会 在 除了记录每个神奇宝贝的名称 类型和训练师之外 系统需要跟踪多种类型的疾病 诊断为神奇宝贝 在预约期间
  • 是否可以避免实现文件中重复类名?

    有没有办法避免Graph 在实现文件中重复 但仍然将类拆分为标头 实现 如 头文件 ifndef Graph H define Graph H class Graph public Graph int n void printGraph v
  • 谷歌云端硬盘托管 URL 发生变化

    我开发了一个网络应用程序 使用谷歌驱动器作为托管平台 如下所述 https support google com drive answer 2881970 hl en 当用户访问时 应用程序一直运行正常 但昨天它开始将该地址重定向到 b21
  • 如何获取两个地点之间的行驶距离?

    我在我的应用程序中使用 GoogleMapv2 api 我想绘制一条从源到目的地的多边形线 并在地图活动上显示旅行时间和距离 但我无法找到它 请帮我 我的代码片段在这里 public class NavigationActivity ext
  • 为什么新的网络版 Dropbox 可以在不刷新页面的情况下更改 URL? [复制]

    这个问题在这里已经有答案了 可能的重复 如何在不离开页面的情况下更改浏览器中显示的 URL 如何像 GitHub 一样进行出色的无刷新页面更改 更改浏览器 URL 和页面内容 无需重新加载且无需使用片段 太神奇了 新的 Dropbox 网页
  • Win32 和 Win64 机器中的 SendInput 按键

    我在 xp 32 位下使用 sendInput 使用 web 服务来推送当前焦点窗口的 F 5 现在在 Vista win64 下我无法获得这个结果 有些文章指出使用 4 位或 8 位的 uint 问题 但这并不能通过差异编译和 Field
  • 求二叉树的直径

    我试图在java中找到二叉树的直径 包含最大节点数的树中任意两个节点之间的路径长度 我的代码片段 public int diametre Node node int d if node null return 0 lh diametre n
  • 使用正确的 pack:// URI 格式

    我有一个 WPF 类库 其中包含一个包含图像的文件夹 图像 在 WPF 应用程序中 我不会使用以下方式引用该文件夹中的图像
  • 在哪里可以找到要添加为参考的 Microsoft.VisualStudio.ExtensionManager?

    我想在使用 VS2013 SDK 安装的 VS2013 中的控制台应用程序上添加以下引用 Microsoft VisualStudio ExtensionManager Microsoft VisualStudio ExtensionMan
  • Xcode 6.1 文件中缺少所需的架构 X86_64

    在 Xcode 6 1 中 我收到 iPhone 6 iPhone 5s iOS 7 1 的错误 其中显示 Undefined symbols for architecture x86 64 OBJC CLASS ClientAuthent
  • 如何在画布上制作弹跳球的动画

    你好 我刚刚开始编写 Java 和 HTML 等代码 所以有时我会遇到困难 因此 我加入 StackOverflow 寻求您的帮助 请对我好一点 我正在尝试使用动画setInterval 并绘制方法来创建一个弹跳球 该球在每帧中移动多个像素
  • OPENCV waitKey()方法返回类型

    我正在尝试使用在线教程学习 OPENCV 用于图像处理项目 opencv 文档说 waitKey 返回一个 int 这应该是按下的键的 ASCII 值 但大多数在线教程都使用以下代码 可以正常编译和运行 if char 27 waitKey
  • Python XML 解析和 getElementsByTagName

    我试图解析以下 xml 并围绕我的业务需求获取我感兴趣的特定标签 我想我做错了什么 不知道如何解析我所需的标签 想要利用 pandas 以便我可以进一步过滤细节 学弟学妹们多多支持 我的 XML 来自 URI
  • Clojure core.logic CLP(FD) 投影 FD 变量

    我正在使用 Clojure 的 core logic CLP FD 库 core logic 版本 0 8 3 开发一种简单的方形打包算法 正方形表示如下 x11 y11 x12 y12 x21 y21 x22 y22 每个正方形表示为其左
  • 如何防止 scanf() 永远等待输入字符?

    我想在控制台应用程序中完成以下任务 如果用户输入一个字符 应用程序将执行以下操作 相应的任务 例如 如果用户输入1 该程序 如果用户输入 将执行任务 1q 程序将退出 如果用户没有输入任何内容 程序将每隔10秒执行一次默认任务 时间不必很严
  • 从 Excel VBA 关闭 Word 应用程序

    我试图在宏开始时关闭所有打开的 Word 应用程序实例 尽管我不知道哪些文档已打开 并且无法将它们设置为对象 这将关闭所有正在运行的 Word 文档 你需要On Error Resume Next以防止在没有运行 Word 应用程序实例时出
  • 如何从webview中获取html内容?

    从 webview 获取 html 代码的最简单方法是什么 我尝试了stackoverflow和google的几种方法 但找不到确切的方法 请说一下具体的方法 public class htmldecoder extends Activit
  • 构造函数中的依赖注入容器

    为什么将容器放在构造函数中这么糟糕 例如 您想要在另一个类 C 的构造函数中解析类 B 因为您需要将类 B 与解析的依赖项一起使用 您开始按照您希望的方式使用类 C 就像使用 B 一样 但使用依赖关系已解决 为什么将容器放在构造函数中这么糟