2012-12-19 10 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として指定します。深い継承階層の場合、別の抽象クラスで "My Type"を生かしてください。

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 'それはあなたがコメント1についてより具体的にするのと同じ方法 – newacct

+0

を動作します)と' 拡張>を?型パラメータがそれを宣言するクラスを限定しているということを厳密に強制することはできませんが、コメントよりも近いです2)私よりもコンパイルできるプログラムがたくさんあります。 –

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、そしてそれが何をされていない、あなたはその子としてその中に任意のDcgNodeを置くことができることを意味するのでDcgNodeのサブクラスであることDagNodeのあなたのアイデアは、安全であることはできません欲しいです。

+0

DcgNodeまたはDagNodeも拡張したい場合はどうすればいいですか? – Sarevok

+0

DcgNodeとDagNodeの両方を格納できるリストを保存したい場合は、それを宣言する必要がありますか?私は生の型を使っているので、コンパイラはそれを宣言すれば警告を表示します。 – Sarevok