問題
、グラフの実装を考えてみましょうSampleGraph<N>
。、グラフノードの実装を考えてみましょうNode extends N
、正しくオーバーライドhashCode
とequals
2つのノード間の論理的平等をミラーリングします。
それでは、私たちはいくつかのプロパティを追加したいとしましょうpはノードに。このような特性は、ノードの論理インスタンスにバインドされている、すなわちためNode n1, n2
、n1.equals(n2)
意味のp( n1
) = P( n2
)
私は単にのフィールドとしてプロパティを追加する場合はNode
、クラス、これは私に起こっています:
- 私は定義し
Node n1, n2
、その結果n1.equals(n2)
が、n1 != n2
- I追加
n1
及びn2
グラフに:n1
論理ノードを挿入するとき、及びn2
縁部の挿入中のノードに参照するとき。グラフは、両方のインスタンスを格納します。 - その後、私はグラフからノードを取得(
n1
返されます)、プロパティ設定P、いくつかの値にその上を。その後、私はグラフのすべてのエッジを横断し、そのうちの一つ(からノードを取得n2
返されます)。プロパティpが私のモデルで論理エラーを引き起こし、設定されていません。
要約すると、現在の動作を:
graph.addNode(n1) // n1 is added
graph.addEdge(n2,nOther) // graph stores n2
graph.queryForNode({query}) // n1 is returned
graph.queryForEdge({query}).sourceNode() // n2 is returned
質問
すべての次の文は、私には合理的なようです。それらのどれも完全に他の人の上に私を説得しないので、私は、ソフトウェアエンジニアリングの規範に基づいたベスト・プラクティスのガイドラインを探しています。
S1 -グラフの実装は貧弱です。それは、同じノード(のインスタンスがある場合、ノードを追加すると、グラフは、常に内部チェックすべきequals
記憶TRUEと評価します)。もしそうであれば、そのようなインスタンスは常にグラフによって使用される唯一の基準であるべきです。
graph.addNode(n1) // n1 is added
graph.addEdge(n2,nOther) // graph internally checks that n2.equals(n1), doesn't store n2
graph.queryForNode({query}) // n1 is returned
graph.queryForEdge({query}).sourceNode() // n1 is returned
S2 - S1のようにグラフの挙動を仮定は誤りです。プログラマは、常にノードの同じインスタンスをグラフに渡されることに注意する必要があります。
graph.addNode(n1) // n1 is added
graph.addEdge(n1,nOther) // the programmer uses n1 every time he refers to the node
graph.queryForNode({query}) // n1 is returned
graph.queryForEdge({query}).sourceNode() // n1 is returned
S3は -プロパティには、正しい方法で実装されていません。これは、クラスの外部にある情報でなければなりませんNode
。以下のようなコレクションは、HashMap<N, Property>
に基づいて、同じオブジェクトとして異なるインスタンスを処理し、うまく動作しますhashCode
。
HashMap<N, Property> properties;
graph.addNode(n1) // n1 is added
graph.addEdge(n2,nOther) // graph stores n2
graph.queryForNode({query}) // n1 is returned
graph.queryForEdge({query}).sourceNode() // n2 is returned
// get the property. Difference in instances does not matter
properties.get(n1)
properties.get(n2) //same property is returned
S4 - S3と同じですが、我々は、実装の内部に隠すことができNode
、このように:
class Node {
private static HashMap<N, Property> properties;
public Property getProperty() {
return properties.get(this);
}
}
編集:以下の現在の行動と暫定ソリューションのためのコードスニペットを追加したスティーブン・Cさんの答え。明確にするために、全体の例では、オープンソースのJavaプロジェクトから実際のグラフデータ構造を使用してから来ています。
私の心のために、それが強いか、弱いの抽象化とAPIの間の選択ダウンしています。
あなたは、強力な抽象化を選択した場合、APIは事実隠すう
Node
オブジェクトはアイデンティティを持っているし、そしてそれらが追加されたときにそれらを正規化しますSimpleGraph
。あなたが弱い抽象化を選択した場合、APIはそれを引き受ける
Node
のオブジェクトが同一性を有し、かつそれがに追加する前に、それらを正規化するために呼び出し側になりますSimpleGraph
。
2つのアプローチは異なるAPI契約につながると異なる実装戦略が必要です。選択は、それが有意である場合...パフォーマンスへの影響を持っている可能性があります。
その後、またはグラフの特定のユースケースが一致しない場合がありAPI設計の細かい詳細があります。
ポイントは、あなたが選択をする必要があるということです。
(このビットは、コレクション使用を決定するようなものでList
、あなたが一緒に効率的に「スプライス」2に示します。どちらのアプローチができるように、独自のリンクリストデータ構造を実装に対して、インタフェースとそのきれいなモデルを可能性があり、アプリケーションの要件に応じて、正しいこと。)
あなたは通常ことに注意してくださいすることができます選択が難しいものかもしれないが、選択をします。たとえば、あなたが他の誰かによって設計されたAPIを使用している場合:
- あなたは、あるとしてそれを使用することもできます。(それを吸います!)
- あなたは、することを選択できますしようとする設計に影響を与えます。(幸運を!)
- あなたは別のAPIに切り替えることを選択することができます。異なるベンダー、すなわち。
- (これはこれが何であるかである場合や好み)あなたはAPIをフォークすることを選択すると、独自の要件にそれを調整することができます
- あなたはゼロから独自のAPIを設計し、実装することを選択することができます。
あなたがいる場合と、本当に選択肢を持っていない、この質問は議論の余地があります。ただ、APIを使用します。
これはオープンソースのAPIであるなら、あなたはおそらくそれを変更するには、設計者を得ることの選択肢を持っていません。重要なAPIのオーバーホールは、他の人々のために多くの仕事を作成する傾向があります。多くすなわち、他の APIに依存してプロジェクトを。責任APIデザイナー/デザインチームは、これを考慮します。さもないと、彼らは彼らのAPIは不安定であるとの評判を得るために、彼らは関連性を失うことを見つけます。
あなたは、彼らが(間違ってのいくつかの定義については)間違ってそれをやっていると思うcosを」...既存のオープンソースのAPIの設計に影響を与えることを目指しているのであれば... ...あなたは 『フォーク』オフはおそらく優れているAPIと結果を扱います。
あなたが「ベストプラクティス」の助言を探している場合は、最終的には、あることに注意してください何のベストプラクティスが存在しません。そして、これは単なる哲学的問題ではありません。これは、あなたが「ベストプラクティス」の助言を探して/を求めて移動し、それに従うならばねじ込まれてしまいます理由についてです。
脚注として:JavaとAndroidの標準クラスライブラリは任意の汎用グラフAPIまたは実装を提供していない、なぜあなたは今まで疑問に思っていますか?そして、なぜ彼らは、サードパーティのライブラリ(グアババージョン20.0)に表示されるように、このような長い時間がかかりましたか?
答えは、このようなAPIは次のようにあるべきかについてのコンセンサスがないことです。あまりにも多くの矛盾のユースケースと要件のセットがあります。