我正在为不同类型的树编写一组集合类。我这样做是为了学习练习,我也希望它能成为一种有用的东西。我真的想以正确的方式做到这一点,所以我一直在阅读Effective Java,我也一直在研究Joshua Bloch通过查看源代码来实现集合类的方式。我似乎对所做的工作有一个很好的了解,但我还有一些事情需要解决。
我有一个Node<T>
接口和一个实现AbstractNode<T>
接口的Node
类。然后我创建了一个GenericNode<T>
(一个可以有0到 n 子节点的节点,它是 n -ary tree)的一部分,它扩展了{{ 1}}并实现AbstractNode<T>
。这部分很简单。
接下来,我创建了一个Node<T>
接口和一个实现Tree<T>
接口的AbstractTree<T>
类。之后,我开始编写Tree<T>
类,扩展GenericTree<T>
并实现AbstractTree<T>
。这是我开始遇到问题的地方。
就设计而言,Tree<T>
只能由GenericTree<T>
类型的节点组成。这包括根。在我的GenericTreeNode<T>
界面中,我有:
Tree<T>
并且public interface Tree<T> {
void setRoot(Node<T> root);
Node<T> getRoot();
List<Node<T>> postOrder();
... rest omitted ...
}
实现了这个接口:
AbstractTree<T>
在public abstract class AbstractTree<T> implements Tree<T> {
protected Node<T> root;
protected AbstractTree() {
}
protected AbstractTree(Node<T> root) {
this.root = root;
}
public void setRoot(Node<T> root) {
this.root = root;
}
public Node<T> getRoot() {
return this.root;
}
... rest omitted ...
}
,我可以:
GenericTree<T>
但这意味着您可以使用public GenericTree(Node<T> root) {
super(root);
}
的任何子类型创建通用树。您还可以将树的根设置为Node<T>
的任何子类型。我希望能够将节点的类型限制为它可以表示的树的类型。要解决这个问题,我可以这样做:
Node<T>
但是,public GenericTree(GenericNode<T> root) {
super(root);
}
仍然接受setRoot
类型的参数。这意味着用户仍然可以使用错误类型的根节点创建树。如何强制执行此约束?我能想到的唯一方法是:
Node<T>
将检查限制为运行时。我不是这个的忠实粉丝。instanceof
并让基类实现此方法。这意味着它不是合同的一部分,任何想要制作新类型树的人都需要记住实现这种方法。有更好的方法吗?
我遇到的第二个问题是setRoot
的返回类型postOrder
。这意味着,如果用户正在List<Node<T>>
对象上操作并调用GenericTree<T>
,则他或她会收到包含postOrder
个对象的列表。这意味着当迭代(使用foreach构造)时,如果他们想要使用仅在该类中定义的方法,则他们将对Node<T>
执行显式强制转换。我不喜欢把这个负担放在用户身上。在这种情况下我有什么选择?我只能考虑从接口中删除该方法,并让子类实现此方法,确保它返回GenericNode<T>
的适当子类型的列表。但是,这再一次将它从合同中删除,并且任何想要创建新类型树的人都必须记住实现此方法。还有更好的方法吗?
答案 0 :(得分:4)
我认为你把马放在马前。
实施Tree<T>
和Node<T>
的几个具体实例。只有在此之后才分析它们共有的实现,并且只有在实现了Abstract
类之后才能实现它们。
修改强>
回答你的第二个问题:
如果简单的Node<T>
没有在Tree
接口中删除它,那么你别无选择,只能向泛型接口声明第二个参数并在其上加上边界,就像这样
public interface Tree<
T,
TNode extends Node< T >
>
{
void setRoot(TNode root);
TNode getRoot();
List<TNode> postOrder();
... rest omitted ...
}
然后是AbstractTree
public abstract class AbstractTree<
T,
TNode extends Node< T >
> implements Tree<T, TNode> {
protected TNode root;
protected AbstractTree(TNode root) {
this.root = root;
}
...
}
然后是GenericTree
public class GenericTree< T >
extends AbstractTree< T, GenericNode< T > >
{
public GenericTree ( GenericNode< T > root )
{
super( root );
}
@Override
public List< GenericNode< T > > postOrder ( )
{
...
}
...
}