2012-12-19 219 views
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. 
} 

是否有更好的方法来设计呢?

回答

0

修改方法如下这样:

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

return (NcgNode) nodeListSrc_.get(n); 
} 
+3

该解决方案不允许调用者使用它返回的具体子类的细节而不执行不安全的强制转换。在路上踢罐子。 –

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 
} 
+0

1)“自限制类型”在Java中不起作用。 2)如果你换成'是AbstractNode >'和'是AbstractNode '和'AbstractDcgNode >'和'AbstractDcgNode '它的工作方式 – newacct

+0

你能否具体谈谈评论1相同) ?我们不能确切地强调一个类型参数限定了声明它的类,但它比评论2)建议更紧密,它允许严格地比我的程序编译更多的程序 - 并且比OP期望的要多。 –

1

只是让你列表有型NcgNode,如

private List<NcgNode> nodeListSrc_ = null; 

你仍然可以把NcgNode的子类到这些列表。

1

你应该做下面的事情。在抽象类(NcgNode)中定义方法,参数化子类型。因此,可以容易地编写addNodegetNode。然后你将有具体的实现(我使用DcgNodeDagNode;不确定这是你想要的)是它的一个子类,它自己参数化。这允许您稍后(见下文)要求节点的子节点与节点类型相同的算法。

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“是一个” DcgNode,那么这意味着你可以把任何DcgNode把它视为其子,这是不是你想。

+0

如果您还想扩展DcgNode或DagNode,该怎么办? – Sarevok

+0

如果我想存储可存储DcgNode和DagNode的列表,我应该声明它吗?如果我使用原始类型声明它,编译器会显示一条警告。 – Sarevok