问题标签 [dependency-inversion]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
4 回答
44307 浏览

php - 依赖注入和依赖倒置的区别

存在两种设计模式,即依赖注入和依赖倒置,网上有文章试图解释差异。但是仍然需要用更简单的语言来解释它。有没有人愿意来?

我需要用 PHP 来理解它。

0 投票
1 回答
141 浏览

c++ - 具有许多类的程序中的依赖倒置 (C++)

我正在尝试将一些旧的 C++ 代码转换为更可测试的形式。为了符合依赖倒置原则(DIP),我会在很多情况下使用依赖注入。

我的问题是如何最好地实例化具体类。这段代码中有 100 个我自己的类。在他的《清洁架构》一书中,罗伯特·马丁认为这些类是易变的,应该在工厂中实例化。但是(参见本书的第 90 页),我要实例化的每个类需要 4 个类。这将意味着 400 节课。

假设为了说明,旧代码有一个类 A(它实例化并使用类 A1 到 A5)、B(B1 到 B10)和 C(类 C1 到 C3)。

在新代码中,您建议如何以及在何处实例化所有具体类?我特别想听听任何在大型 C++ 程序中处理过此类问题的人的意见。谢谢。

布鲁斯

0 投票
1 回答
133 浏览

mvvm - 关注点分离、依赖倒置和 AutoMapper 投影

关于将 AutoMapper.EF6 用于投影的 MVVM 项目,我很难将数据访问层和视图模型层的关注点分开,并在这些层之间保持依赖关系反转。

假设我们有这些层和类。

现在,在 中EntityFormVM,我IQueryable<TEntity>从一个IEntityDA实例中获取一个,并将其投影到一个列表中TEntityVM,最后调用IEntityDA.Dispose(). 这样,DA就暴露了一个IQueryable!不知道对不对!VM 负责处理上下文,因为 DA 不知道工作何时完成!

另一方面,我有一些替代方案,例如反转 DA 和 VM 之间的依赖关系。因此,我将把EntityDA<TEntityVM, TEntity>结果投射到哪些项目中TEntityVM并返回它们。但是,DA 将取决于 VM!

这里的最佳做法是什么?

0 投票
2 回答
257 浏览

c# - 依赖倒置:如何最好地管理抽象的版本控制

在高代码重用环境中应用依赖反转时如何在 .Net 中对抽象进行版本化

我有兴趣转向在 .Net 中使用依赖倒置,但遇到了一些令我困惑的事情。我不认为它与 DIP 的特定方法或提供者有关,而是更多可能其他人已经解决的基本问题。我要解决的问题最好按照下面的场景逐步说明。

假设/限制

预先提出的一个相当大的假设或限制是,我的开发团队坚持将我们部署的程序集保留为一个且只有一个程序集版本的规则,特别是版本“1.0.0.0”。到目前为止,为了简单起见,我们不支持将我们开发的任何给定程序集的多个程序集版本部署在服务器上。这可能是限制性的,并且可能有很多很好的理由来摆脱它,但无论如何,这是我们目前使用的规则。因此,考虑到这种做法,继续下面。

设想

  • 您有一个 IDoStuff 接口,包含在具有 2 个方法的抽象程序集 Stuff.Abstractions.dll 中。
  • 您使用具有 2 种方法的显式实现 IDoStuff 的类来编译组件 A.dll。
  • 您将 A.dll 移至生产使用,程序集版本 1.0.0.0,程序集文件版本 1.0.0.0。
  • 您将 Interface.dll 移至 prod,程序集版本 1.0.0.0,程序集文件版本 1.0.0.0。
  • 一切正常。时间流逝。
  • 您将另一个方法(例如“DoMoreStuff”)添加到 IDoStuff 接口,以便不同的组件 B 可以调用它。(牢记接口隔离 OO 原则,假设 DoMoreStuff 方法在这个相对较小的 IDoStuff 接口中是有意义的。)
  • 您现在在 Stuff.Abstractions.dll 中拥有带有 3 个方法的 IDoStuff,并且您已经构建了组件 B 以使用新的第 3 个方法。
  • 您将 Stuff.Abstractions.dll 移动到生产使用(升级它)、程序集版本 1.0.0.0、程序集文件版本 1.0.0.1。(请注意,文件版本会增加,但程序集版本和强名称保持不变)
  • 您将 B.dll 移至生产使用,程序集版本 1.0.0.0,程序集文件版本 1.0.0.17。
  • 你不会对 A.dll 做任何事情。您认为此时不需要进行任何更改。

现在,您调用的代码试图在之前工作的同一生产服务器上执行 A.dll。在运行时,依赖反转框架将 IDoStuff 接口解析为 A.dll 中的一个类并尝试创建它。问题是 A.dll 中的类实现了现已灭绝的 2 方法 IDoStuff 接口。正如人们所预料的那样,您会得到一个像这样的异常:

来自程序集“程序集 A.dll 的强名称”的类型“A.dll 中的 IDoStuff 类”中的方法“DoMoreStuff”没有实现。

当我必须向现有接口添加方法时,我可以想到两种方法来处理这种情况:

1) 更新每个使用 Stuff.Abstractions.dll 的功能提供程序集,以实现新的“DoMoreStuff”方法。这似乎是用艰难的方式做事,但以蛮力的方式会很痛苦。

2)弯曲上述假设/限制并开始允许存在多个程序集版本(至少对于抽象定义程序集)。这会有点不同,并在我们的服务器上制作更多的程序集,但它应该允许以下最终状态:

A.dll 依赖于 stuff.abstractions.dll,Assembly 版本 1.0.0.0,Assembly File 版本 1.0.0.22(AFV 与识别构建无关) B.dll 依赖于 stuff.abstractions.dll,Assembly 版本 1.0。 0.1,程序集文件版本 1.0.0.23(AFV 除了识别构建之外无关紧要)两者都能够在同一台服务器上愉快地执行。

如果两个版本的 stuff.abstractions.dll 都安装在服务器上,那么一切都应该很好。A.dll 也不需要更改。每当它接下来需要修改时,您可以选择实现存根并升级接口,或者什么也不做。如果它只需要它们,也许最好将其保留为它首先可以访问的 2 种方法。作为附带的好处,我们知道任何引用 stuff.abstractions.dll,版本 1.0.0.0 的东西只能访问 2 个接口方法,而 1.0.0.1 的用户可以访问 3 个方法。

是否有更好的方法或可接受的部署模式来进行版本控制抽象?

如果您尝试在.Net 中实现依赖倒置方案,是否有更好的方法来处理版本控制抽象?如果你有一个单一的应用程序,它看起来很简单,因为它都包含在内——只需更新界面用户和实施者。我试图解决的特定场景是一个高代码重用环境,其中有许多依赖于许多组件的组件。依赖倒置确实有助于分解事情并使单元测试感觉不像系统测试(由于紧密耦合的层)。

0 投票
1 回答
252 浏览

inversion-of-control - 通过参数名称解​​决 Castle Windsor 依赖项

鉴于

那么我该如何实现以下目标

Foo 和 Bar 应该分别获取 publicService 和 secretService 的实例,完全基于它们的构造函数参数的名称。

0 投票
1 回答
285 浏览

swift - Swift - 使第三方类型符合我自己的协议,但有冲突的要求

这是归结的情况:

假设 Alice Allman 编写的第三方框架提供了一个非常有用的类:

Bob Bell 编写的另一个框架提供了一个不同的类:

在运行时,可能需要这些类中的任何一个,具体取决于用户决定使用的硬件。因此,根据依赖倒置原则,我不希望自己的类型依赖AATrackpadBBMouse直接依赖。相反,我想定义一个协议来描述我需要的行为:

然后让我自己的类型使用该协议:

我希望能够使用一个实例BBMouse作为光标输入,如下所示:

但为了编译它,我必须追溯符合BBMouse我的协议:

现在我已经符合BBMouse我的CursorInput协议,我的代码可以编译,我的架构就是我想要的方式。我在这里没有问题的原因是我认为where_is_the_mouse该属性的名称很糟糕,我很高兴再也不会使用该名称。然而,有AATrackpad一个不同的故事。我碰巧认为 AlicecursorLocation完美地命名了她的属性,并且如您所见,我希望能够为我的协议要求使用相同的名称。我的问题是它AATrackpad不用CGPoint作此属性的类型,而是使用称为AAPoint. 我的协议要求 ( cursorLocation) 与 的现有属性具有相同名称AATrackpad但类型不同的事实意味着我不能追溯符合CursorInput

正如该片段中的注释所说,这段代码无法编译,即使编译了,我也会在运行时面临无限递归,因为我无法具体AATrackpad引用cursorLocation. 如果这样的事情可行,那就太好了(self as? AATrackpad)?.cursorLocation,但我认为这在这种情况下没有意义。尽管如此,协议一致性甚至不会首先编译,因此为了解决无限递归而消除歧义是次要的。

考虑到所有这些背景,我的问题是:

如果我使用协议(被广泛推荐,这是有充分理由的)来构建我的应用程序,那么我使用某种第三方具体类型的能力真的取决于希望这个第三方开发人员不会分享我的口味吗?命名约定?


注意:“只需选择一个与您要使用的类型不冲突的名称”的答案不会令人满意。也许一开始我只有BBMouse并且没有冲突,然后一年后我决定我也想添加支持AATrackpad。我最初选择了一个很棒的名字,现在它在我的应用程序中普遍使用 - 为了一种新的具体类型,我是否必须在任何地方更改它?当我想添加对 的支持时会发生什么CCStylusTablet,现在与我选择的任何新名称冲突?我是否必须再次更改协议要求的名称?我希望你明白我为什么要寻找比这更合理的答案。

0 投票
2 回答
2156 浏览

javascript - 如何为 es5 风格的“类”实现 Typescript 接口?

我们可以为 es6 类实现接口的方式非常简单:

问题是:如何为这个“类”实现相同的接口:

我尝试将 Dog 的类型定义为 IDog: const Dog: IDog。没用。

所以,我需要它来实现依赖倒置,我不知道如何用 es5 类做到这一点。我看到 Classical Inheritance 样式是 Javascript 中的“反模式”,所以我决定以旧方式创建类,并且需要帮助实现 Typescript 接口。

0 投票
2 回答
1655 浏览

oop - 依赖倒置原则[DIP]中的“抽象不应该依赖于细节。细节应该依赖于抽象”是什么意思?

在问这个问题之前,我想说stackoverflow中的这个问题与我的问题非常相似,但这个概念仍然不清楚很混乱。

我试图理解依赖倒置原理,但我无法完全理解它?

以下是 DIP 所说的两点

A. 高级模块不应该依赖于低级模块。两者都应该依赖于抽象。B. 抽象不应该依赖于细节。细节应该取决于抽象。

我可以掌握第一点,但我无法掌握第二点,看起来两者都一样。在 stackoverflow 和其他网站中进行大量搜索后,我能够理解两者都试图说不同的东西,但我无法理解。

让我们考虑一个例子:

让我们考虑用于计算员工工资的 SalaryCalculator 类[高级模块]。它使用 BonusCalculator [高级模块] 来计算工资,如下所示。由于 SalaryCalculator 使用的是 BonusCalculator,它违反了“高级模块不应该依赖于低级模块”的第一点。两者都应该依赖于抽象”。

在此处输入图像描述

所以我们在两者之间引入了抽象,如下所示:

在此处输入图像描述

这里的细节[低级和高级模块]依赖于抽象,而抽象不依赖于细节。那么在 DIP 中,第二点试图说明什么? 如果两者都相同,为什么将其设为两点?

如果有人给我一个代码示例,那将非常有用。

0 投票
1 回答
609 浏览

go - 我们应该在哪里定义多消费者场景中的 Go 接口?生产者中的界面如何显示通用性?

有人可以给我一个具体的例子来说明这个建议吗?

https://github.com/golang/go/wiki/CodeReviewComments#interfaces

这就是我遵循它的方式吗?



是否可以在 2 个地方复制接口以满足“定义消费者在哪里消费”。


使用界面来表现一般性怎么样?它定义了接口而不是它被消耗的地方

例如 hash/crc32 和 hash/adler32 实现 hash.Hash32

0 投票
1 回答
52 浏览

solid-principles - 关于 SOLID 编程实践的实用问题

关于依赖倒置原则的一个实际问题:

我们希望在许多库或 DLL 中构建我们的系统。

如果较低级别库的组件或类应该依赖于抽象,无论是 Iinterface 还是纯抽象类,并且被调用方可执行文件或更高级别库也应该依赖于该抽象而不是具体类,那么应该将其放入哪个库抽象被编译?

是的,当然,具体类是由工厂连接和提供的......

从逻辑上讲,它属于可执行或更高级别的库,但也许出于实际目的,它应该编译到较低级别的库中。