【问题标题】:When is it okay to depend on concrete classes?什么时候可以依赖具体的类?
【发布时间】:2019-12-12 04:37:05
【问题描述】:

今天我被问到一个我找不到答案的问题,所以我在这里寻求您的帮助! 依赖倒置原则指出,具体类和抽象都应该依赖于抽象,对吧?

尽管如此,我们仍然依赖于像 IntegerString 这样的框架类。有没有很好的答案来解释为什么可以?

我知道我们不应该仅仅因为它可能会发生微小的变化而重新发明轮子,而且我提到的这些特定类很可能永远不会以用户会注意到的方式发生变化(他们的界面不会改变)。

【问题讨论】:

  • 务实地说,抽象会产生开销并提供灵活性。您必须在成本和收益之间找到正确的权衡。如果您不会从增加的灵活性中受益(例如,因为您不太可能用该类代替其他任何东西),那么就只剩下开销了。经验有助于预测何时成本超过收益。

标签: oop design-patterns solid-principles dependency-inversion


【解决方案1】:

另外一点,请注意您引用的元素实际上在 java.lang 中,即没有 import 语句,因此可以说不依赖于使用这些类型引起的任何内容,除了您使用 Java 的事实.

一旦您退出 java.lang,我相信您通常最好使用 DIP,即始终更喜欢使用 List<T> 而不是使用 ArrayList<T>

问题是将“组件”(或模块/包...)的依赖跨界限制为仅功能依赖(即抽象、Java 中的接口)。在某些时候,您确实需要具体的实现,这些实现必须至少使用一些数据结构来构建,即使它只是基本 int 类型的数组。这并不违反 DIP。

@jaco0646 的回答中建议使用普通旧数据,不违反 DIP 是一种边界;在大多数情况下,您可以使用显式传递您正在考虑的结构字段的签名,而不是将它们打包到单个对象中;这种方法确实更通用,例如你可以在没有那个 POD 类的情况下实现它,也许依赖于一些关系 DBMS,你可以与用任何语言编写的代码等进行交互......

但是在实践中,在签名中使用 POD 是有意义的,因此如果我向 POD 添加一个字段,这将自动传播到所有使用该结构的签名。其中一些函数可能不会使用新字段,因此我们现在给它们提供了太多信息(我们正在泄漏,关于严格的“需要知道”)。不过,在许多情况下,选择这种方法可能是一个务实的答案。

如果我们看看例如webservices,一般倾向于认为 POD 不是服务签名中的问题, 使用它们有助于保持客户端兼容,即使结构中出现了一些新字段。

【讨论】:

    【解决方案2】:

    在 OOP 中,对象是数据和行为的封装组合。数据被隐藏;行为暴露。 DIP 应用的正是这些对象。理想情况下,这些对象应该在 Composition Root 中实例化,这是唯一依赖于对象具体类的组件。

    显然,为了实例化它们,某些东西必须依赖于具体的类。这通常是您的 DI 容器。这个想法是容器的唯一关注点是实例化具体类,所以其他一切都可以服从 DIP。

    另一方面,与对象相反,我们有原始数据结构。这些类没有(必然)被封装,暴露了它们的数据,并且很少或没有行为。依赖于数据结构的具体类是可以的。这些不是 OOP 意义上的“对象”。 DIP 不适用于数据结构。对具体数据结构的依赖应该是本地的;但是,不会暴露在拥有这些依赖项的对象之外。

    请注意,您经常会在代码中看到“混合体”:既充当对象又充当数据结构的类。他们暴露了他们的数据和行为。 Hybrid 是两全其美的,无论你是否对它们应用 DIP,更大的问题是它们试图服务于两个相反的目的并违反封装。

    【讨论】:

      猜你喜欢
      • 2018-12-10
      • 2012-05-18
      • 2020-04-05
      • 2014-03-28
      • 2020-05-19
      • 2021-03-23
      • 2020-10-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多