5

我有一个应用程序可以对节点和边 G(N,E) 的图执行各种分析算法。节点和边的属性因应用程序而异,并根据图的类型和属性的性质形成继承层次结构。例如,节点层次结构的根可以表示最一般的无向循环图(NcgNode)。NcgNode 的一个子类可能代表有向循环图(DcgNode),其次是 DagNode 等。可应用于 DAG 的算法与 NCG 的算法不同,但反之亦然。树根的一个关键行为是添加和检索图的相邻节点。问题是如何在不创建“未经检查”的异常的情况下做到这一点?

代码的简洁版本可能如下所示:

import java.util.ArrayList;
import java.util.List;

public class NcgNode {
    private List<NcgNode> nodeList_ = null;
    private List<? extends NcgNode> nodeListSrc_ = null;
    private List<? super NcgNode> nodeListSink_ = null;

    public <N extends NcgNode> void addNode(N node) {
        if (nodeList_ == null) {
            nodeList_ = new ArrayList<NcgNode>();
            nodeListSrc_ = nodeList_;
            nodeListSink_ = nodeList_;
        }
        nodeListSink_.add(node);
    }

    @SuppressWarnings("unchecked")
    // Any way to avoid this?
    public <N extends NcgNode> N getNode(int n) {
        if ((nodeList_ == null) || (n >= nodeList_.size()))
            return null;
        // causes unchecked warning:
        return (N) nodeListSrc_.get(n);
    }
}

class DcgNode extends NcgNode {
    // enables DCG algorithms, etc
}

class DagNode extends DcgNode {
    // enables DAG algorithms, etc.
}

有没有更好的方法来设计这个?

4

4 回答 4

1

只需让您的列表具有 NcgNode 类型,例如

private List<NcgNode> nodeListSrc_ = null;

您仍然可以将 NcgNode 的子类放入这些列表中。

于 2012-12-19T02:22:29.073 回答
1

您应该执行以下操作。将方法定义在抽象类 ( NcgNode) 中,根据子类的类型进行参数化。因此,addNode并且getNode可以很容易地编写。然后,您将拥有特定的实现(我使用DcgNodeand DagNode;不确定这是否是您想要的)成为 this 的子类,对其自身进行参数化。这允许您稍后(见下文)算法要求节点的子节点与节点的类型相同。

public abstract class NcgNode<N> {
    private List<N> nodeList_ = null;

    public void addNode(N node) {
        if (nodeList_ == null) {
            nodeList_ = new ArrayList<N>();
        }
        nodeList_.add(node);
    }

    // Any way to avoid this?
    public N getNode(int n) {
        if ((nodeList_ == null) || (n >= nodeList_.size()))
            return null;
        return nodeList_.get(n);
    }
}

class DcgNode extends NcgNode<DcgNode> {
    // enables DCG algorithms, etc
}

class DagNode extends NcgNode<DagNode> {
    // enables DAG algorithms, etc.
}

//...
static <N extends NcgNode<N>> void someAlgorithm(N node) { }

DagNode您成为的子类的想法DcgNode是不安全的,因为如果DagNode"is-a" DcgNode,那么这意味着您可以将任何DcgNode作为它的子类放入其中,这不是您想要的。

于 2012-12-19T10:31:15.940 回答
0

如下修改您的方法:

public NcgNode getNode(int n) {
  if ((nodeList_ == null) || (n >= nodeList_.size())) {
  return null;
}

return (NcgNode) nodeListSrc_.get(n);
} 
于 2012-12-19T01:59:45.680 回答
0

查看“自界类型”。(编辑:不确定我是否理解这里的反对票)

您的根类应该是抽象的,并且实际的节点类型N应该是该类的类型参数,如

public abstract class AbstractNode< N extends AbstractNode< N > > {
    private List< N > nodeList_ = null;

    public synchronized void addNode( N node ) {
        if ( nodeList_ == null )
            nodeList_ = new ArrayList< N >();
        nodeList_.add(node);
    }

    public N getNode( int n ) {
        if ( nodeList_ == null || n >= nodeList_.size() )
            throw new NoSuchElementException();
        return nodeList_.get( n );
    }
}

然后具体的子类可以提供它们自己的类型作为 N。对于深度继承层次结构,使用另一个抽象类保持“我的类型”。

class NcgNode extends AbstractNode< NcgNode > {
}

abstract class AbstractDcgNode< N extends AbstractDcgNode< N > > extends AbstractNode< N > {
    // enables DCG algorithms, etc
}

class DcgNode extends AbstractDcgNode< DcgNode > {
}

class DagNode extends AbstractDcgNode< DagNode > {
    // enables DAG algorithms, etc
}
于 2012-12-19T02:12:32.293 回答