【问题标题】:Implementation question involving implementing an interface涉及实现接口的实现问题
【发布时间】:2010-05-25 22:19:05
【问题描述】:

我正在为不同类型的树编写一组集合类。我将其作为一个学习练习,我也希望它成为有用的东西。我真的很想以正确的方式做到这一点,所以我一直在阅读Effective Java,并且我也一直在研究 Joshua Bloch 通过查看源代码实现集合类的方式。我似乎对正在做的事情有一个大致的了解,但我还有一些事情要解决。

我有一个Node<T> 接口和一个实现Node 接口的AbstractNode<T> 类。然后我创建了一个扩展AbstractNode<T> 和实现Node<T>。这部分很容易。

接下来,我创建了一个Tree<T> 接口和一个实现Tree<T> 接口的AbstractTree<T> 类。之后,我开始编写一个扩展AbstractTree<T> 并实现Tree<T>GenericTree<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&lt;T&gt; 实现了这个接口:

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&lt;T&gt;,我可以拥有:

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

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

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

但是,setRoot 仍然接受 Node&lt;T&gt; 类型的参数。这意味着用户仍然可以使用错误类型的根节点创建树。如何强制执行此约束?我能想到的唯一方法是:

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

有没有更好的办法?

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

【问题讨论】:

  • 你确定你需要setRoot方法吗?我记得 Effective Java 的一个建议是 favor immutability
  • @Alexander 这是真的。这实际上是我一直在考虑的另一个想法——setRoot 是否真的有必要。我开始倾向于它没有是必要的。第二个问题呢?

标签: java oop inheritance interface implementation


【解决方案1】:

我认为你是本末倒置。

实现Tree&lt;T&gt;Node&lt;T&gt; 的几个具体实例。只有在那之后分析它们有什么共同的实现,然后再实现你的 Abstract 类,如果它们在那时仍然有意义的话。

编辑

回答你的第二个问题:

如果简单的Node&lt;T&gt; 没有在你的Tree 接口中剪切它,那么你别无选择,只能为泛型接口声明第二个参数并在其上设置边界,像这样

public interface Tree<
  T,
  TNode extends Node< T >
>
{

    void setRoot(TNode root);

    TNode getRoot();

    List<TNode> postOrder();

    ... rest omitted ...
}

然后是抽象树

public abstract class AbstractTree<
  T,
  TNode extends Node< T >
> implements Tree<T, TNode> {

  protected TNode root;

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

  ...
}

然后是通用树

public class GenericTree< T >
  extends AbstractTree< T, GenericNode< T > >
{

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

  @Override
  public List< GenericNode< T > > postOrder ( )
  {
    ...
  }
  ...
}

【讨论】:

  • 这实际上是我首先做的,我确定了与实现无关的常用方法。我所剩下的就是我上面谈到的案例 - 即试图弄清楚如何返回节点列表。
  • 完美。这正是我一直在寻找的。非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-19
  • 2020-08-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-03
  • 2015-11-23
  • 1970-01-01
相关资源
最近更新 更多