1

关于组合和面向对象的问题:

我正在尝试为一个类实现更多功能(以 Java TreeMap 为例)。

public class TreeMap<K,V> 
   extends AbstractMap<K,V>
   implements NavigableMap<K,V>, Cloneable, Serializable

使用组合是这样做的方法,所以我必须首先创建一个可重用的转发类,它将包装类的功能,同时让它只这样做,以便它可以在其他地方使用未来。

public class ForwardingNavigableMap<K,V> implements NavigableMap<K,V>
{
 ...
}

然后,我将继续创建一个包装类,该类继承新创建的 可重用转发类,如下所示:

public class BetterTreeMap<K,V> extends ForwardingNavigableMap<K,V>
{
 /* some new cool features here */
}

如果 TreeMap 包含我的类中需要的许多优良特性,那可能不是 NavigableMap 接口的一部分,会发生什么?然后我应该继续为 TreeMap 声明我自己的接口,并在我的可重用类中实现它吗?任何输入在这里表示赞赏。

4

6 回答 6

2

假设您不打算将其作为公共 API(这意味着您不将其发送给第 3 方并期望他们使用它),您可以执行以下操作。

鉴于您(可能)需要访问 TreeMap 特定的方法,但也可能稍后决定将继承更改为 TreeMap 以外的其他内容,只要您不编写任何依赖于作为 TreeMap 的类的代码(例如,从不除了“扩展 TreeMap”之外,请参阅 TreeMap),那么您可以安全地使用扩展。这将要求您编写一个提供 TreeMap 方法的接口。

如果您发现您不想起诉 TreeMap 并想稍后使用其他东西,因为您没有在任何地方引用 TreeMap 都可以。然后,您将剩下对 TreeMap 特定方法的所有调用……如果所有这些调用同时消失,而您不再从 TreeMap 扩展,那么您就可以开始了。如果他们不这样做,那么您将需要编写自己的来实现所需的方法。

如果您从 TreeMap 更改,要找出您需要什么,您将注释掉您放入接口中的所有方法,如果代码使用空接口编译,您就可以使用,如果不是,您需要添加缺少方法回到接口。如果您决定扩展的类没有提供您需要做的缺失方法(或者您确实必须从 TreeMap 扩展)。

另一种解决方案是提前确定您是否真的需要 TreeMap。我不确定我是否想在一个我不确定我的数据结构需要什么的项目中走得太远。

于 2009-04-05T15:01:22.733 回答
1

将您自己的所有新方法放在一个新接口中,并创建一个也实现该接口的类。

就在这里

public class MyMap implements MyInterface, NavigableMap {
...
}

然后你可以让这个类扩展你想要的类,但我认为最好让 MyMap 的私有成员属于 TreeMap 类,因为你只公开那些你真正想要的方法,而不是 TreeMap 额外拥有的所有方法。

编写转发方法需要大量工作,但例如 Eclipse 具有良好的重构功能,允许您自动生成它们。

于 2009-04-05T18:12:26.517 回答
1

这里的问题是,在这个例子TreeMap中,它就像一个接口。您可以通过覆盖其所有转发方法来处理它。这不像是一个空的状态TreeMap。但是,这是一种脆弱的方法,因为不会处理新方法(或您错过的方法)。

也许您的课程不需要是Map. 您可以创建一个适合您的代码的接口,但一个asMap/ asSortedMap/asNavigableMap用于库和非特定代码。

于 2009-04-05T13:52:07.097 回答
1

如果 TreeMap 包含我的类中需要的许多优良特性,那可能不是 NavigableMap 接口的一部分,会发生什么?

这是在这种情况下使用组合的问题。如果您发现自己制作了一堆包装器方法,它们除了在 TreeMap 上调用相同的方法之外什么都不做,那就是支持继承的论据。因此,如果您有大量看起来像的方法

public Set<K> keySet()
{
    return myTreeMap.keySet();
}

您可能只想扩展 TreeSet 以免费获取其所有方法,然后覆盖您要更改的方法。

如果您正在设计的类在内部使用TreeMap,并且客户端程序不需要知道这一点,那么您应该使用组合。如果您的类具有一些添加或更改功能的 TreeMap,则使用继承。

于 2009-04-05T14:27:12.783 回答
1

最简单的方法是扩展现有的类

public class MyTreeMap<K,V> extends TreeMap<K,V> {
   // add your overridden or extra methods here.
}

我建议你不要让事情变得比他们需要的更复杂。

如果这不合适,也许您可​​以解释您要达到的目标。

于 2009-04-05T11:07:37.317 回答
1

如果这些很酷的新功能将在您将使用的其他数据结构上实现,那绝对是。

如果没有,尽量避免用无用的接口重载你的类。尽量减少杂乱。

于 2009-04-05T11:08:24.273 回答