【问题标题】:Why does the Collections class contain standalone (static) methods, instead of them being added to the List interface?为什么 Collections 类包含独立(静态)方法,而不是添加到 List 接口?
【发布时间】:2010-06-21 23:52:28
【问题描述】:

对于Collections 中所有将List 作为第一个参数的方法,为什么这些方法不只是List 接口的一部分?

我的直觉是:给定一个 List 对象,该对象本身应该“知道”如何对其自身执行操作,例如 rotate()、shuffle() 或 reverse()。但是,作为一名 Java 程序员,我必须检查 List 接口中的方法以及 Collections 类中“那边”的静态方法,以确保我使用的是规范的解决方案。

为什么有些方法作为静态独立方法放置在 Collections 类中,而不是添加到 List 接口中(并且可能因此由某些现有或可能的基类实现)?

我试图更好地理解 Java 集合框架背后的设计决策。

我忽略了一些引人注目的面向对象设计原则吗?或者这种区分仅仅是出于某种实际的性能原因?

【问题讨论】:

  • 这可能是一个有趣的面试问题,所以感谢您的灵感:)

标签: java collections


【解决方案1】:

关键在于,如果给定合适的原始操作(删除、设置等),则可以实现一次更高级的操作(排序、随机播放、二分搜索),而不是由每个单独的操作来实现列表实现。

实际上,java.util.Collections 就像 .NET 的 Enumerable 类 - 充满了可用于任何集合的通用方法,因此它们可以共享单个实现并避免重复。

【讨论】:

  • 您仍然可以在诸如 AbstractList 之类的基类中实现它们,而不是在每个 List 实现中。并不是说你想要,只是它会避免在每个 List 实现中实现它们
  • @objects - 但是当我自己实现 List 接口但我扩展 AbstractList (因为也许我在我的问题域中扩展了其他东西)我'我必须编写自己的 sort()、shuffle() 等实现。
  • 那是真的,只是表明它不会被强制在每个列表实现中实现。正如我在回答中提到的那样,不依赖内部的操作通常在单独的类中会更好。
【解决方案2】:

列表接口方法背后的理性

  1. List 接口是 Java 运行时的核心部分,在推出您自己的 List 实现时,要完全实现所有成员已经有点繁重了。因此,添加与列表定义不直接相关的额外方法有点无关紧要。如果您在 List 实现中需要这些方法,为什么不子类化接口然后再需要它们?
  2. 如果您打算在 1.3 版中出现并通过添加新实用程序方法向 List 接口添加功能,您将破坏该接口的所有过去实现者。
  3. 从领域驱动设计的角度来看,集合中的实用方法不是列表的正常领域的一部分。
  4. 关于 OO 设计原则,我认为区分应用程序 OO 设计和语言运行时 OO 设计非常重要。

Java 的作者现在可能会做非常不同的事情,因为他们对 API 的多年使用有后见之明。也就是说,C# IList 接口与 Java 非常相似,C# 的作者确实有这种观点。

【讨论】:

  • +1 用于提及向后兼容性:您不能向接口添加方法。 Collections 类中的一些方法是后来添加的。
【解决方案3】:

这当然是某种程度的判断。我认为要考虑的主要权衡是:当您向接口添加方法时,该接口的每个实现者都必须编写代码来实现它。

如果该方法的语义使得接口的不同实现会以非常不同的方式最好地实现这些语义,那么最好将它放在接口中。 (当然,如果语义根本无法用接口中的其他方法来定义,那么它必须是接口中自己的方法。)

另一方面,如果语义可以根据接口中的其他方法来定义,并且接口的实现者会倾向于一遍又一遍地编写相同的代码,那么最好使将接口实例作为参数的实用方法。

【讨论】:

    【解决方案4】:

    它们是实用方法,而不是核心列表功能。如果您添加了所有可以对 List 执行的操作,List 界面就会变得臃肿。而且 Collections 中的操作不需要了解 List 的内部结构,它们在公共接口上操作,因此可以愉快地存在于外部类中。

    【讨论】:

    • 什么是“效用”,什么是“核心”,有什么具体的原则吗?还是当前的设计只是某人的最佳判断?
    • 核心基本上是列表所需的最小操作集,例如。添加一个元素,删除一个元素。实用方法更多地在 List 本身上进行操作,而无需了解其内部结构。
    • @Aaron F,无论 List 的实现如何,“shuffle”或“random”的实现都是相同的。无论您的 List 是由数组还是链表支持,“shuffle”或“random”都是一样的。
    【解决方案5】:

    这里有两种解释:

    1. 历史:集合类是在 List 接口之后创建的。设计人员选择保留现有接口的向后兼容性。否则很多开发人员将不得不更改他们的代码。

    2. 逻辑:您所谈论的方法不需要有关 List 实现的内部知识,并且可以在任何实现它的集合上实现。

    【讨论】:

    • #2 不太正确。 Collection 中有一些方法,其参数专门调用一个 List,而且只调用一个 List。例如java.sun.com/javase/6/docs/api/java/util/…
    • @Aaron F,这不是 eugener 在这里所指的。他的意思是,无论列表如何实现(“内部知识”),排序或改组的算法都是相同的。
    猜你喜欢
    • 1970-01-01
    • 2011-05-10
    • 1970-01-01
    • 1970-01-01
    • 2011-02-13
    • 2011-04-26
    • 1970-01-01
    • 2012-06-05
    • 1970-01-01
    相关资源
    最近更新 更多