为什么注入类而不是接口被认为是不好的做法?

Ade*_*lin 4 refactoring dependency-injection

将类注入其他类被认为是不好的,其中一些论点是很难模拟一个类,并且将对象耦合在一起。

但是我看到许多开发人员每天都会这样做,并且大多数模拟框架都非常擅长模拟类并提供测试模拟,那么这是什么问题呢?

J. *_*ger 8

抽象类型(如接口)比具体类倾向于更稳定(随时间变化较小)。依靠更稳定的事物通常风险较小。将它们放在一起,相较于具体类,通常依赖于接口的风险较小。

我还发现,当我更多地依赖接口时,更容易检测到行为的重大变化。当接口必须更改时,发生了重要的事情。当发生不重要的事情(令人惊讶地)导致接口发生变化时,我将其解释为提高设计抽象水平的信号。对于具体的类,此信号对我而言不那么“清晰”,清晰,明显。

与直接在客户端模块中实例化这些风险相比,注入一个具体的类所产生的风险要少得多。如果您不担心注入具体类的风险,请花一会儿,然后等待该风险成为问题。然后,您可以决定介意多少。幸运的是,随着重构的进行,从具体类中提取接口是相当安全的。只要记住,当需要时,提取出客户端所需的最小接口,不要盲目地将每个具体的类方法放入接口中。(接口隔离原理。)


Gho*_*ica 5

某些(有影响力的)人,例如 Robert Martin,声称在源代码中使用具体类的名称基本上是您应该避免的,以防止“耦合太紧”。

让我引用他关于“敏捷原则”的书:

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

并进一步:

考虑依赖于低级模块的高级模块的含义。它是包含应用程序的重要策略决策和业务模型的高级模块。这些模块包含应用程序的标识。然而,当这些模块依赖于较低级别的模块时,对较低级别模块的更改会对较高级别的模块产生直接影响,并可以迫使它们依次更改。这种困境是荒谬的!应该影响低级详细模块的是高级策略设置模块。包含高级业务规则的模块应该优先于包含实现细节的模块,并且独立于包含实现细节的模块。高级模块不应该以任何方式依赖低级模块。

但当然,在现实中,总是有平衡的。当你非常确信

  1. 你的班级很可能不会随着时间的推移而改变
  2. 你的课程不是最终的,你可能想要模拟的方法也不是最终的

那么更喜欢接口而不是类就没有多大意义了。

但是 - 如果有疑问,接口是更好的方法。

我不得不经常向人们解释,他们使用 PowerMock 以允许模拟某些最终类/方法的想法是错误的方法;更好的答案是将参数的类型更改为某个接口。

  • 事实上,关键是要依赖稳定的东西而不是不稳定的东西。具体类越稳定,依赖它的风险就越小;尽管假设该类不是值对象,但没有太多理由将依赖项留在具体类上,因为添加接口的新实现(当需要更改时)比实际更容易且风险更小涉及子类化。 (2认同)