扩展 Guava 集合
Extending Guava collections
我想扩展 LinkedHashMultimap (Guava 16.0.1),主要是为了添加 return 常用的预填充地图的方法。
public class MyMap extends LinkedHashMultimap<String, Object> {
}
但是,据我了解,大多数 Guava 集合都是最终的,而那些不是最终集合的则不会公开 public 构造函数。这个设计决定的可能原因是什么?实现我的目标的最佳方法是什么?我能想到的最好的方法是在我的 class 中包装 Multimap 方法,但这远非理想。
编辑:
一些用户指出了不允许继承的正当理由。为了稍微扩展一下问题,我想指出几件事。
如果publicAPI不推荐继承,为什么Java自己的集合class不是final的?
假设我广泛使用以下 class:
LinkedHashMultimap, BiConsumer>
现在,这是一口。如果我可以:
public class ConsumerMap extends LinkedHashMultimap<Class<? extends BaseEntity>, BiConsumer<? extends BaseEntity, ? extends Object>> {
}
然后我可以在我的代码中使用 ConsumerMap 而不是那个怪物。我相信仅可读性就足以证明继承的合理性。
机会是:
- 在Java8中的接口中添加默认方法(你不能这样做,因为集合类型由Guava库定义),
- 扩展实现(同样你不能,因为实现大多是最终的)
- 为外部助手 class 提供您想要的方法
这些 类 设计为不可扩展 。因为继承本质上破坏了封装,所以当 类 无法扩展时,它使 API 更干净。 (此处相关主题:Good reasons to prohibit inheritance in Java?)
您通常可以通过使用合成来解决这个问题。
回答您的后续问题:
关于 Java 集合 API,我认为有两种选择:类 像 ArrayList
或 HashMap
被设计为扩展或然后这只是一个 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.
中吸取的教训
我想扩展 LinkedHashMultimap (Guava 16.0.1),主要是为了添加 return 常用的预填充地图的方法。
public class MyMap extends LinkedHashMultimap<String, Object> {
}
但是,据我了解,大多数 Guava 集合都是最终的,而那些不是最终集合的则不会公开 public 构造函数。这个设计决定的可能原因是什么?实现我的目标的最佳方法是什么?我能想到的最好的方法是在我的 class 中包装 Multimap 方法,但这远非理想。
编辑:
一些用户指出了不允许继承的正当理由。为了稍微扩展一下问题,我想指出几件事。
如果publicAPI不推荐继承,为什么Java自己的集合class不是final的?
假设我广泛使用以下 class:
LinkedHashMultimap
现在,这是一口。如果我可以:
public class ConsumerMap extends LinkedHashMultimap<Class<? extends BaseEntity>, BiConsumer<? extends BaseEntity, ? extends Object>> {
}
然后我可以在我的代码中使用 ConsumerMap 而不是那个怪物。我相信仅可读性就足以证明继承的合理性。
机会是:
- 在Java8中的接口中添加默认方法(你不能这样做,因为集合类型由Guava库定义),
- 扩展实现(同样你不能,因为实现大多是最终的)
- 为外部助手 class 提供您想要的方法
这些 类 设计为不可扩展 。因为继承本质上破坏了封装,所以当 类 无法扩展时,它使 API 更干净。 (此处相关主题:Good reasons to prohibit inheritance in Java?)
您通常可以通过使用合成来解决这个问题。
回答您的后续问题:
关于 Java 集合 API,我认为有两种选择:类 像 ArrayList
或 HashMap
被设计为扩展或然后这只是一个 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.