- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
所以通常建议使用依赖注入(inject)来帮助进行单元测试,以解决类依赖于其他类的问题。这听起来不错,但让我来谈谈我面临的问题。
这是一个没有 DI 的常规实现:
class Upper{
Middle middle = new Middle();
}
class Middle{
Lower lower = new Lower();
}
class Lower{
}
现在让我们从底部开始。 Middle 依赖于 Lower,我们真的不想这样,所以我们将为 Lower 创建一个冗余接口(interface)并将其传递给 Middle 的构造函数:
class Middle{
Lower lower;
public Middle(ILower lower){
this.lower = lower;
}
}
interface ILower{
}
class Lower : ILower{
}
这听起来不错,对吧?好吧,不是真的。我见过的大多数例子都到此为止了,忘记了某些东西需要使用 Middle 类。现在我们必须更新 Upper 才能兼容:
class Upper{
Middle middle = new Middle(new Lower());
}
这似乎不是很有用...我们所做的只是将问题提升了一个级别,并创建了一个不寻常的依赖关系:Upper 现在依赖于 Lower 了吗?这绝对不是改进。
我一定是错过了好处,但似乎 DI 只是转移了问题而不是解决了问题。事实上,这也让代码更难理解。
此外,这是一个“完整”的实现:
interface IUpper {
}
class Upper : IUpper {
Middle middle;
public Upper(IMiddle middle){
this.middle = middle;
}
}
interface IMiddle {
}
class Middle : IMiddle {
Lower lower;
public Middle(ILower lower){
this.lower = lower;
}
}
interface ILower {
}
class Lower : ILower {
}
不过,我只是在转移问题。要使用 Upper,我需要:
new Upper(new Middle(new Lower()));
现在我依赖 3 个类!
最佳答案
依赖注入(inject)只是指您创建类的方式,以便为它们提供它们的依赖项(“注入(inject)”到它们中),而不是类创建它们自己的依赖项的实例。
DI 是否只是将创建类实例的问题转移到了其他地方?
是的,这正是它的作用,这很好。
您使用的每个类实例都必须在某处实例化。问题是实例化发生在哪里,以及它是否使您的类或多或少易于管理和测试。
权衡是,如果一个类直接创建它所依赖的其他类的实例,那么当然,为该外部类调用构造函数要简单得多。你创建了那个类,它创建了一堆其他类,然后它们创建了更多类,等等。但是每个直接创建其他类的类都变得越来越难进行单元测试。当一个类的行为包括它创建的类的行为、它们创建的类的行为等等时,您不能只为一个类的行为编写测试。因此,作为对更简单的构造函数调用的返回,您得到的代码几乎无法测试,也很难维护。
依赖注入(inject)将类的依赖项的创建移出类。这使得每个单独的类 更易于测试和维护,但正如您所观察到的那样,它会产生不同的问题。现在您的构造函数调用要复杂得多,会创建各种嵌套依赖项。
解决这个问题的是依赖注入(inject)容器,也称为 IoC 容器。一些示例包括 Windsor、Autofac、Unity,还有更多。有了这些,您只需为任何类可能依赖的每个单独接口(interface)指定一个实现。
例如(这是 Windsor 语法,但它们都有点相似)
container.Register(Component.For<InterfaceA, ImplementationToUse>());
container.Register(Component.For<InterfaceB, ImplementationForThis>());
container.Register(Component.For<InterfaceC, ImplementationToUse>());
然后,如果你调用
var thingINeed = container.Resolve<InterfaceA>();
(这实际上不是我们从容器中获取类实例的方式,但那是另一回事了。)
它将弄清楚它需要创建哪些类来传递实现的构造函数。如果这些类有更多的依赖关系,它将创建这些,依此类推。
现在您已经两全其美了。您可以根据需要创建任意数量的小型可测试类,其中包含大量嵌套依赖项,所有这些都取决于抽象。如果您要尝试直接调用它们的构造函数,那将非常复杂,远远超出您问题中的示例。但你不必那样做。您可以单独考虑每个类 - 它的作用是什么,它直接依赖于哪些接口(interface)?
你仍然有一些复杂性。您现在不必调用一堆构造函数,而是必须向容器注册各个依赖项。但这是一个很好的权衡,你会领先,因为你的类是解耦和可测试的。
关于c# - 依赖注入(inject)不只是将问题转移到别处吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48981858/
我已阅读有关依赖注入(inject)的信息。然后来了 构造函数注入(inject), setter/getter 注入(inject) 二传手注入(inject) 接口(interface)注入(in
我正在研究依赖注入(inject)模式。我看过很多例子,其中一个典型的例子是使用 XxxService/XxxRepository 作为例子。但是在我看来,按照UML的概念,类XxxRepositor
我开始使用 Google Guice。 我有一个简单的问题: javax.inject 的 @Inject 注释和 com.google.inject 的 有什么区别@Inject 一个 ? 谢谢。
当使用构造函数注入(inject)工厂方法时,依赖的属性不会得到解析。但是,如果在解析依赖的组件之前解析了工厂方法,则一切都会按预期工作。此外,当仅使用属性注入(inject)或构造函数注入(inje
我有这样的事情: class Root { public Root(IDependency dep) {} } class Dependency:IDependency { p
听完Clean Code Talks ,我开始明白我们应该使用工厂来组合对象。因此,例如,如果 House有一个 Door和 Door有一个 DoorKnob , 在 HouseFactory我们创建
情况:我需要在一些 FooClass 中进行惰性依赖实例化,所以我通过 Injector类作为构造函数参数。 private final Injector m_injector; public Foo
在编写代码时,我们应该能够识别两大类对象: 注入(inject)剂 新品 http://www.loosecouplings.com/2011/01/how-to-write-testable-cod
这个问题是关于 Unity Container 的,但我想它适用于任何依赖容器。 我有两个具有循环依赖关系的类: class FirstClass { [Dependency] pub
如果我有 10 个依赖项我需要注入(inject)并且不想在构造函数中有 10 个参数,我应该使用哪种注入(inject)模式? public class SomeClass { privat
我在使用 Angular2 DI 时遇到了问题。我尝试将一个类注入(inject)另一个类,它引发了以下错误: 留言:"Cannot resolve all parameters for 'Produ
对依赖注入(inject)还很陌生,我想弄清楚这是否是一种反模式。 假设我有 3 个程序集: Foo.Shared - this has all the interfaces Foo.Users -
我正在尝试了解 Angular 14 的变化,尤其是 inject()我可以将模块注入(inject)功能的功能,我不需要为此创建特殊服务..但我想我弄错了。 我正在尝试创建一些静态函数来使用包 ng
希望这个问题不是太愚蠢,我试图掌握更高级的编程原理,因此试图习惯使用 Ninject 进行依赖注入(inject)。 因此,我的模型分为几个不同的 .dll 项目。一个项目定义了模型规范(接口(int
我最近一直在大量使用依赖注入(inject)、测试驱动开发和单元测试,并且开始喜欢上它。 我在类中使用构造函数依赖,这样我就可以为单元测试注入(inject)模拟依赖。 但是,当您实际需要生产环境中的
我有下面的代码来使用 Guice 进行依赖注入(inject)。第一个是使用构造函数注入(inject),而另一个是直接在字段上方添加 @Inject。这两种方式有什么区别吗? Guice官网似乎推荐
这个问题在这里已经有了答案: Angular2 Beta dependency injection (3 个答案) 关闭 7 年前。 我正在使用 angular2 测试版。并在使用 @Inject
有没有可能做这样的事情? (因为我尝试过,但没有成功): @Injectable() class A { constructor(private http: Http){ // <-- Injec
我很恼火必须通过 Constructor 传递管道对象,因为我想为业务实体或要传递的值保留构造函数参数。 所以我想通过 setter ,但只要这些 setter 没有被填充,我的包含依赖项的对象就不应
假设我有这个: SomePage.razor: @inject Something something @page "/somepage" My Page @code { // Using
我是一名优秀的程序员,十分优秀!