首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >涉及实现接口的实现问题

涉及实现接口的实现问题
EN

Stack Overflow用户
提问于 2010-05-25 22:19:05
回答 1查看 215关注 0票数 4

我正在为不同类型的树编写一组集合类。我这样做是作为一个学习练习,我也希望这是一些有用的东西。我真的很想用正确的方式来做这件事,所以我一直在阅读有效Java,我也一直在研究Joshua通过查看源代码实现集合类的方式。我似乎对正在做的事情有一个公平的想法,但我仍然有一些事情要解决。

我有一个Node<T>接口和一个实现Node接口的AbstractNode<T>类。然后我创建了一个GenericNode<T> (一个节点可以有0到n个子节点,它是n进制树的一部分),它扩展了AbstractNode<T>并实现了Node<T>。这部分很简单。

接下来,我创建了一个Tree<T>接口和一个实现Tree<T>接口的AbstractTree<T>类。之后,我开始编写GenericTree<T>类,扩展AbstractTree<T>并实现Tree<T>。这就是我开始有问题的地方。

就设计而言,GenericTree<T>只能由GenericTreeNode<T>类型的节点组成。这包括根。在我的Tree<T>接口中有:

代码语言:javascript
复制
public interface Tree<T> {

    void setRoot(Node<T> root);

    Node<T> getRoot();

    List<Node<T>> postOrder();

    ... rest omitted ...
}

而且,AbstractTree<T>实现了这个接口:

代码语言:javascript
复制
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>中,我可以拥有:

代码语言:javascript
复制
public GenericTree(Node<T> root) {
   super(root);
}

但这意味着您可以使用Node<T>的任何子类型创建泛型树。还可以将树的根设置为Node<T>的任何子类型。我希望能够将节点的类型限制为它可以表示的树的类型。为了解决这个问题,我可以这样做:

代码语言:javascript
复制
public GenericTree(GenericNode<T> root) {
   super(root);
}

但是,setRoot仍然接受Node<T>类型的参数。这意味着用户仍然可以创建具有错误类型的根节点的树。如何执行此约束?我唯一能想到的办法是:

  • 执行将检查限制为运行时的instanceof。我不是这个的超级粉丝。
  • 从接口中删除setRoot并让基类实现此方法。这意味着它不是契约的一部分,任何想要创建一种新型树的人都需要记住实现这个方法。

有更好的办法吗?

第二个问题涉及postOrder的返回类型,即List<Node<T>>。这意味着,如果用户在GenericTree<T>对象上操作并调用postOrder,他或她将收到一个由Node<T>对象组成的列表。这意味着当迭代(使用foreach构造)时,如果希望使用仅在该类中定义的方法,则必须执行对GenericNode<T>的显式强制转换。我不喜欢把这个负担强加给用户。在这种情况下我有什么选择?我只能考虑从接口中删除该方法,并让子类实现此方法,同时确保它返回适当的Node<T>子类型的列表。但是,这再次将其从契约中删除,任何想要创建新类型树的人都必须记住实现此方法。有更好的办法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2010-05-25 22:59:52

我觉得你把马车放在马前面。

实现Tree<T>Node<T>的两个具体实例。只有在此之后,分析它们有哪些共同的实现,然后才实现您的Abstract类,如果它们在这一点上仍然有意义的话。

编辑

回答你的第二个问题:

如果简单的Node<T>没有在Tree接口中剪切它,那么您别无选择,只能将第二个参数声明为泛型接口,并在其上设置一个边界,如下所示

代码语言:javascript
复制
public interface Tree<
  T,
  TNode extends Node< T >
>
{

    void setRoot(TNode root);

    TNode getRoot();

    List<TNode> postOrder();

    ... rest omitted ...
}

然后是AbstractTree

代码语言:javascript
复制
public abstract class AbstractTree<
  T,
  TNode extends Node< T >
> implements Tree<T, TNode> {

  protected TNode root;

  protected AbstractTree(TNode root) {
    this.root = root;
  }

  ...
}

然后是GenericTree

代码语言:javascript
复制
public class GenericTree< T >
  extends AbstractTree< T, GenericNode< T > >
{

  public GenericTree ( GenericNode< T > root )
  {
    super( root );
  }

  @Override
  public List< GenericNode< T > > postOrder ( )
  {
    ...
  }
  ...
}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2908952

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档