表示依赖注入相反的技术术语?


12

这更多是术语(技术写作),而不是纯粹的技术问题。我正在尝试围绕我们的应用程序中扩展依赖项注入编写一个重构建议(并将其分配给我自己)。虽然我们确实使用Spring来自动装配Bean,但是仍然存在使用实例化Bean的实例,这些实例MyClass obj = new MyClass(...)可以完全注入。我想使我的建议使用优雅的命名法,并用适当的术语指代DI的设计模式。

“紧密耦合”是否足以作为DI的反义词?


1
是的,耦合描述了在其他类中使用显式类名的行为以及代码库的结果状态。
凯莉安·佛斯

11
不,紧密耦合仅描述所得代码的属性,而不与DI相反。您可以使用DI并由于完全不同的原因仍然具有紧密的耦合。
布朗


@EricKing炫耀。+1。
candied_orange

1
“依赖吸引”
SeldomNeedy

Answers:


30

不能。紧密耦合远不止依赖注入处理。

依赖注入将实现的决定外部化。这对解耦有很长的路要走,但是耦合不仅限于此。

依赖注入的一个很好的反义词是对依赖进行硬编码。当在一个行为对象内构造(使用新的或直接使用某些工厂)时,您已经将两个不同的关注点混淆在一起。服务定位器有助于解耦,但让您与服务定位器本身耦合。

耦合不仅仅是将构造和行为分开。如果我有101种必须按某种特定顺序从A类到B类调用的方法,则我紧密联系在一起。无关紧要的构造和行为是多么完美的分离。

耦合是两个对象相互依存的量度。任何导致难以在不影响另一个的情况下进行更改的因素都将导致耦合。依赖注入可以帮助实现这一点,但这还不是全部。


是的,硬编码(依赖项)与注入(在运行时)相反,这正是我要建议的,您的速度也比我快一点。
布朗

7
@DocBrown我有时希望这个地方不要太强调快速。我想听听你怎么说。
candied_orange

好的答案-依赖注入并不意味着解耦。相信否则会导致糟糕的发展
Ant P

1
@CandiedOrange也许有人应该在meta中建议将答案隐藏一段时间。和/或在公众视野中隐藏选票N数小时...或直到选择答案为止。我知道当一个答案已经有10票而其他5个答案都没有时,并不完全客观!
svidgen

1
@svidgen在meta上搜索“西方最快的枪支”。这个问题已经有很长的历史了。
candied_orange

6

严格地说,依赖注入只有真正反对依赖注入 -因此,任何依赖管理策略,是不依赖注入。

[不需要]耦合,尽管不完全是正交的问题,但可以通过两种方式发生或缓解。这些都与DependencyClass

public DependencyInjectedConstructor(DependencyClass dep) {
  dep.do();
}

public DependencyLookupConstructor() {
  var dep = new DependencyClass();
  dep.do();
}

DependencyLookupConstructorDependencyClass在这种情况下耦合到特定对象。但是,它们耦合到DependencyClass。真正的弊端(如果这里有一个)不一定是耦合,DependencyLookupConstructor如果DependencyClass突然需要注入自己的依赖项,那就需要改变1

但是,此构造函数/类的耦合更为松散:

public DependencyLocatingConstructor() {
  var dep = ServiceLocator.GetMyDoer();
  dep.do();
}

如果您使用的是C#,上面的代码将允许您在被调用时ServiceLocator返回任何内容GetMyDoer(),只要它具有do()DependencyLocatingConstructor拥有的一切即可do()。您可以获得编译时签名验证的好处,而无需耦合到完整的接口2

所以,选择你的毒药。

但基本上,如果有一个特定的“依赖关系注入”对立面,那么“依赖关系管理策略”将是另外一回事。除其他外,如果您在对话中使用以下任何内容,我会认为它不是“依赖注入”:

  • 服务定位器模式
  • 依赖定位器/位置
  • 直接对象/依赖关系构造
  • 隐藏的依赖
  • “非依赖注入”

具有讽刺意味的是,DI在较高级别上解决的一些问题是由于在较低级别上过度使用DI造成的。我一直很乐意在所有不必要的复杂性上工作,从而适应了不必要的复杂性因为这些地方实际上帮助了很多地方……我承认,不良的表现使我产生了偏见。

2.使用服务位置还可以使您轻松地通过调用代码中的功能角色来指定相同类型的不同依赖项,同时仍然很大程度上不了解依赖项的构建方式。假设您需要解决UserIUser出于不同的目的:例如,Locator.GetAdministrator()对比Locator.GetAuthor()-或其他。我的代码可以在不知道其支持什么接口的情况下询问其功能需求。


2
为救恩DependencyInjectedConstructor(DependencyClass dep)是DependencyClass可能是一个接口或抽象类。这就是为什么让C#编码人员使用接口前缀(如中)令我感到悲伤的原因IDependency。作为客户,依赖项实际上不是我的事。只要不构建它,我所需要知道的就是如何与它交谈。这是别人的问题。
candied_orange

重点是,DI仍然会将您耦合到该接口,并且完全不需要DependencyClass是抽象接口。它要求构造/配置/位置逻辑存在于“其他地方”。...好吧,更重要的是,这个问题的关键在于,DI并非“紧密耦合的反面” :)
svidgen

实际上...我可能会说DI一定会使您耦合到一个接口,甚至在C#中也可能会超出范围。虽然,我在C#中避免使用它们,但我的印象是我也可以接受dynamic参数。(但是var,如果有内存,则不是参数。)因此,对于C#中的DI,我我要么必须针对接口进行编码,要么就不得不完全放弃编译时验证。
svidgen

对象耦合到接口。是否使用interface关键字。这就是正确的接口。您必须耦合的所有内容。您煮熟的是实现细节和不需要的额外内容。我们可以通过使用interface关键字来使客户正式了解世界,“我所需要的就是这个”。但是我们不必。哎呀,我们可以在某些语言中进行鸭子打字。
candied_orange

我不确定我们是否完全不同意。但是,澄清一下……是的,对象内部耦合到它们自己的接口。但是,如果接口被显式命名,则接口本身仅施加依赖关系耦合。在C#中,使用dynamicvar从定位器获取对象,让我们忽略该接口,并使用可以满足do()需要的任何类,无论该类是否实现了某些IDoer接口。换句话说,如果我们有A-> B <-C,DI将A从C解耦,但是它要求A和C都耦合到B,并且即使D会阻止D的使用do()
svidgen

2

我不知道有特定的,广泛接受的行业术语,但是想到的替代方法包括内部实例创建内部依赖项创建本地依赖项本地范围的依赖项


2
我喜欢,instance creation但不够具体。DI创建实例,但是通过控制器而不是在应用程序级别。也许internal instance creation
两栖的2016年

1

我会去依赖封装。这表示依赖项被锁定而不是再次访问并离开。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.