关于构图和面向对象的问题:
我正在尝试为类实现更多功能(Java TreeMap作为示例)。
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, Serializable
使用合成是way to go on this,所以我必须先创建一个 可重用的转发类,它将包装类的功能,同时 同时使它只做它,以便它可以在未来的其他地方使用。
public class ForwardingNavigableMap<K,V> implements NavigableMap<K,V>
{
...
}
然后我将继续创建一个继承新创建的包装类 reusable forwarding class,如下:
public class BetterTreeMap<K,V> extends ForwardingNavigableMap<K,V>
{
/* some new cool features here */
}
如果TreeMap包含我需要的许多优秀功能,会发生什么 我的类,可能不是NavigableMap界面的一部分?我应该 继续为TreeMap声明我自己的界面,并在我的可重用类中实现它?这里的任何意见都表示赞赏。
答案 0 :(得分:2)
假设您不打算将其作为一个pulic API(意味着您没有将其发送给第三方并期望他们使用它),您可以执行以下操作。
鉴于您(可能)需要访问TreeMap特定方法,但也可能稍后决定将继承更改为TreeMap以外的其他方式,只要您不编写任何依赖于该类的代码作为TreeMap(例如,除了“extends TreeMap”之外,永远不要引用TreeMap,那么使用extends是安全的。这将要求您编写一个提供TreeMap方法的接口。
如果你发现你不想起诉TreeMap并想在以后使用别的东西,那么你就不会在任何地方引用TreeMap。然后,您将完成对TreeMap特定方法的所有调用...如果所有这些方法在您不再从TreeMap扩展的同时消失,那么您就可以继续了。如果他们不这样做,那么您需要编写自己的方法来实现所需的方法。
如果你从TreeMap改变了你需要或不知道你需要什么,你会注释掉你放入所做界面的所有方法,如果代码用空接口编译你很好,如果不是你需要将缺少的方法添加回界面。如果你决定扩展的类没有提供你需要做的工作(或者你必须从TreeMap扩展)。
另一种解决方案是提前弄清楚你是否真的需要TreeMap。我不确定我是否想要进入一个项目,我不确定我的数据结构需要什么。
答案 1 :(得分:1)
最简单的方法是扩展现有的类
public class MyTreeMap<K,V> extends TreeMap<K,V> {
// add your overridden or extra methods here.
}
我建议你不要让事情变得比他们需要的更复杂。
如果这不合适,也许你可以解释一下你想要实现的目标。
答案 2 :(得分:1)
如果这些很酷的新功能将在您将使用的其他数据结构上实现,绝对是。
如果没有,请尽量避免使用无用的接口重载类。保持杂乱无章。
答案 3 :(得分:1)
这里的问题是,在这个示例中,TreeMap
就像一个接口。您可以通过覆盖其所有转发方法来对待它。它不像空的TreeMap
中有很多状态。然而,这是一种脆弱的方法,因为新的方法(或你错过的方法)不会被处理。
也许你的班级不一定是Map
。您可以创建适合您代码的界面,但asMap
/ asSortedMap
/ asNavigableMap
用于库和非特定代码。
答案 4 :(得分:1)
如果TreeMap在我的课程中包含了许多我需要的精细功能,那么会发生什么?这可能不是NavigableMap界面的一部分?
这是在这种情况下使用合成的问题。如果你发现自己制作了一堆包装器方法,除了在TreeMap上调用相同的方法之外什么都不做,那就是支持继承的参数。因此,如果您有大量的方法看起来像
public Set<K> keySet()
{
return myTreeMap.keySet();
}
您可能只想扩展TreeSet以免费获取所有方法,然后覆盖您想要更改的方法。
如果你正在设计的类在内部使用一个TreeMap,而客户端程序不需要知道它,那么你应该使用合成。如果您的类是 TreeMap,并且添加或更改了一些功能,那么请使用继承。
答案 5 :(得分:1)
将所有自己的新方法放在新接口中,并创建一个实现此接口的类。
这将是
public class MyMap implements MyInterface, NavigableMap {
...
}
然后你可以让这个类扩展你想要的类,但是我认为最好让MyMap的私有成员属于TreeMap类,因为你只暴露那些你真正想要的方法而不是那些TreeMap另外的那些方法。
编写转发方法需要大量工作,例如Eclipse具有良好的重构,允许您自动生成它们。