2012-12-19 220 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