扩展 Guava 集合

Extending Guava collections

我想扩展 LinkedHashMultimap (Guava 16.0.1),主要是为了添加 return 常用的预填充地图的方法。

public class MyMap extends LinkedHashMultimap<String, Object> {
}

但是,据我了解,大多数 Guava 集合都是最终的,而那些不是最终集合的则不会公开 public 构造函数。这个设计决定的可能原因是什么?实现我的目标的最佳方法是什么?我能想到的最好的方法是在我的 class 中包装 Multimap 方法,但这远非理想。

编辑:

一些用户指出了不允许继承的正当理由。为了稍微扩展一下问题,我想指出几件事。

  1. 如果publicAPI不推荐继承,为什么Java自己的集合class不是final的?

  2. 假设我广泛使用以下 class:

LinkedHashMultimap, BiConsumer>

现在,这是一口。如果我可以:

public class ConsumerMap extends LinkedHashMultimap<Class<? extends BaseEntity>, BiConsumer<? extends BaseEntity, ? extends Object>> {
}

然后我可以在我的代码中使用 ConsumerMap 而不是那个怪物。我相信仅可读性就足以证明继承的合理性。

机会是:

  1. 在Java8中的接口中添加默认方法(你不能这样做,因为集合类型由Guava库定义),
  2. 扩展实现(同样你不能,因为实现大多是最终的)
  3. 为外部助手 class 提供您想要的方法

这些 类 设计为不可扩展 。因为继承本质上破坏了封装,所以当 类 无法扩展时,它使 API 更干净。 (此处相关主题:Good reasons to prohibit inheritance in Java?

您通常可以通过使用合成来解决这个问题。

回答您的后续问题:

关于 Java 集合 API,我认为有两种选择:类 像 ArrayListHashMap 被设计为扩展或然后这只是一个 API 设计缺陷。我怀疑是后者;但在 API 发布后无法恢复此设计选择。也许只有抽象的 类 如 AbstractList 应该被声明为非最终的?

可能 Guava 团队认为像您提供的这样的用例非常罕见,因此不值得为继承 (YAGNI) 添加支持。

Josh Bloch 的

This talk——他参与了 JavaAPI 和 Guava 的设计——是关于该主题的精彩演讲。

正如其他人所指出的,您应该更喜欢委托而不是继承。

要实现您想要的 class,您要做的是扩展 ForwardingSetMultimap,使用 LinkedHashMultimap 作为委托。这是一个外观示例:

public final class MyMap extends ForwardingSetMultimap<String, Object> {
  private final SetMultimap<String, Object> delegate =
      LinkedHashMultimap.create();

  @Override public SetMultimap<String, Object> delegate() {
    return delegate;
  }

  // add your methods here
}

旁白:你问"If inheritance if not recommended in public API, how come Java's own collection classes are not final?"

我认为答案基本上是 Java 自己没有 collection classes final 是一个错误(注意:其中一些,特别是较新的,实际上是 final)。正如@Mick Mnemonic 指出的那样,Josh Bloch(设计原始 collection APIs 的人)参与了 Guava 的 collection APIs 的设计:Guava 的设计决策 API 反映了从原来的 collection APIs.

中吸取的教训