【问题标题】:Extendable double-linked tree implementation in JavaJava中可扩展的双链树实现
【发布时间】:2011-12-06 14:27:23
【问题描述】:

我想通过一些额外的数据来扩展现有的双链树实现。

因此,我可以重构基本的 TreeNode 实现,但我想要一个单独的扩展 TreeNode 实现,因为在我的实际场景中,构建 ExtandedTreeNode 将比构建基本的要昂贵得多TreeNode,额外数据仅在某些用例中是必需的。

基本代码

这是我在 Java 中实现可扩展双链树的第一个基本方法:

基本树节点界面:

interface TreeNode
{
    // tree node getters:

    TreeNode getParent();

    List<? extends TreeNode> getChildren();

    // tree node setters:

    void setParent(TreeNode parentNode);

    void addChild(TreeNode childNode);

    // some basic operations:

    boolean isSelectable();

    // [...]
}

扩展树节点接口:

interface ExtandedTreeNode extends TreeNode
{
    // narrow types of tree node getters of super-interface:

    @Override
    ExtandedTreeNode getParent();

    @Override
    List<? extends ExtandedTreeNode> getChildren();

    // narrowing types of tree node setters of super-interface is not possible!

    // some additional operations:

    boolean isRemoveable();

    // [...]
}

基本树节点实现:

class TreeNodeImpl implements TreeNode
{
    private TreeNode parent;

    private List<TreeNode> children = new ArrayList<TreeNode>();

    private boolean isSelectable;

    //
    // implement tree node getters:
    //

    @Override
    public TreeNode getParent()
    {
        return parent;
    }

    @Override
    public List<? extends TreeNode> getChildren()
    {
        return children;
    }

    //
    // implement tree node setters:
    //

    @Override
    public void setParent(TreeNode parent)
    {
        this.parent = parent;
    }

    @Override
    public void addChild(TreeNode childNode)
    {
        children.add(childNode);
    }

    //
    // implement basic operations:
    //

    @Override
    public boolean isSelectable()
    {
        return isSelectable;
    }

    // [...]
}

扩展树节点实现:

class ExtandedTreeNodeImpl implements ExtandedTreeNode
{
    private ExtandedTreeNode parent;

    private List<ExtandedTreeNode> children = new ArrayList<ExtandedTreeNode>();

    private TreeNode treeNode;

    private boolean isRemoveable;

    public ExtandedTreeNodeImpl()
    {
        treeNode = new TreeNodeImpl();
    }

    //
    // implement tree node getters:
    //

    @Override
    public ExtandedTreeNode getParent()
    {
        return parent;
    }

    @Override
    public List<? extends ExtandedTreeNode> getChildren()
    {
        return children;
    }

    //
    // implement tree node setters:
    //

    @Override
    public void setParent(TreeNode parent)
    {
        this.parent = (ExtandedTreeNode) parent; // <--- How to avoid this type cast!!
    }

    @Override
    public void addChild(TreeNode childNode)
    {
        children.add((ExtandedTreeNode) childNode); // <--- How to avoid this type cast!!
    }

    //
    // implement basic operations by delegating to composite TreeNode:
    //

    public boolean isSelectable()
    {
        return treeNode.isSelectable();
    }

    // [...]

    //
    // implement additional operations:
    //

    @Override
    public boolean isRemoveable()
    {
        return isRemoveable;
    }

    // [...]
}

问题

对我来说,类型层次结构对于只读和非树节点特定的方法看起来很棒,但它对于 setter setParent(..)addChild(..) 会泄漏。特别是ExtandedTreeNode 的风险类型转换非常邪恶,我想摆脱它。

我想过将setParent(..)addChild(..) 方法提取到另外两个独立的接口,例如TreeNodeWriteableExtandedTreeNodeWriteable,但也许有一些更好的设计解决方案。

有人知道可以解决我的可写树节点特定设置器问题的设计模式或蓝图吗?

【问题讨论】:

    标签: java generics tree


    【解决方案1】:

    您可以使用泛型。如下定义你的树节点:

    interface TreeNode<N extends TreeNode> {
    
        N getParent();
    
        List<N> getChildren();
    
        void setParent(N parentNode);
    
        void addChild(N childNode);
    
    }
    

    现在您的 TreeNodeImpl 将如下所示: class TreeNodeImpl implements TreeNode&lt;TreeNode&gt;

    而 ExtendedTreeNodeImpl 的定义如下:

    class ExtendedTreeNodeImpl implements ExtendedTreeNode&lt;ExtendedTreeNode&gt;

    这些类的参数化方法将使用特定类型:TreeNodeExtendedTreeNode,因此不需要强制转换。

    【讨论】:

    • 感谢您的回复。事实上,TreeNode 的模板可以工作,但我看到以下缺点: * 就像@BenSchulz 提到的那样,代码到处都是类型参数,尽管实际上不需要模板。
    【解决方案2】:

    可以使用 self 类型模式。不利的一面是,您的所有代码都充满了(大多数情况下)您并不真正需要的类型参数。

    例子:

    interface TreeNode<S extends Node<S>> { // S is the self type
        void setParent(S parent);
        void addChild(S child);
    }
    interface ExtendedTreeNode extends Node<ExtendedTreeNode> {}
    

    编辑: Related blog post by Stephen Colebourne

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-25
      • 1970-01-01
      • 2011-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多