たくさんのモジュールがあります。これらのモジュールを、完全で重複しないさまざまなカテゴリに分類できます。たとえば、Animal
、Vegetable
、Mineral
として表現できるIDを持つ3つのカテゴリ。さらに、これらのカテゴリをサブカテゴリに分類します。サブカテゴリも、明確で完全であり、重複しません。たとえば、Mammal
、Reptile
、Legume
、Root
、Rock
、Gem
として表現できるID 。最後に、これらのカテゴリの下には、モジュール自体があります。 Cat
、Dog
、Iguana
、Bean
、Quartz
、Emerald
など.
これが私の一般的な使用例です:
このデータをどのように保存すればよいですか?
他のいくつかの関連する事実:
これが私が現在していることです:
Map<Category, CategoryDataStructure>
を含むクラスがあります。このクラスは、要件#2で使用するためのデータの個別のCollection<Module>
viewも保持します。CategoryDataStructure
には、SubCategoryDataStructure
を介してチェーンの下方にメソッド呼び出しを送信するチェーンされた委譲メソッドがあります。CategoryDataStructure
には、要件#5で使用される集計データも格納されます。それは機能しますが、正直なところかなり扱いにくいです。全体はステートフル/ミュータブルであり、変更が困難です。新しい動作を追加したい場合は、多くの場所に追加する必要があります。現在、データ構造自体にも多くのビジネスロジックがあります。委任方法。また、親データ構造は、特定のモジュールと必要に応じてその親データ構造、および必要に応じてその親のデータ構造を作成するために多くのビジネスロジックを実行する必要があります。
どういうわけか、データ管理ロジックをデータ構造自体から切り離そうとしていますが、ネストが複雑なためです。ここに私が検討してきた他のいくつかのオプションがあります:
Map<Category, Map<Subcategory, Module>>
を作成し、すべてのコードを配置して、その状態を別のクラスに保持します。これを行う際の私の懸念は要件#1と#2です。これで、同じデータを表す2つの異なるデータ構造が作成されるため、ビューの一貫性を保つのが難しくなります。ここでの中心的な問題は、IDに基づいてオブジェクトが階層的に配置されているが、非階層的な方法で使用していることです。
例えは、ファイルタイプに基づいてファイルをディレクトリに保存することですが、各ディレクトリを検索し、タイプ以外の基準に基づいて特定のディレクトリのみをロードします。
どういうわけか、データ管理ロジックをデータ構造自体から切り離そうとしていますが、ネストが複雑なためです。ここに私が検討してきた他のいくつかのオプションがあります:
これは良い目標であり、大きなリファクタリングなしで責任を分割し始める簡単な方法があります: Visitors を使用します。
階層内の特定の要素のみを検査または操作する必要がある場合、そのロジックをビジター自体に配置するという考え方です。次に、複数の訪問者を記述し、それぞれが異なる要素で動作し、異なるアクションを実行することができます。
ロジックの各ユニットは、特定のビジターに対して自己完結型になりました。これにより、コードのSRP性が向上します。操作の実行方法を変更する必要がある場合は、そのロジックを実装するビジターでのみ変更します。オブジェクト階層は、必要なデータを公開するための表面的な変更を除いて、同じままである必要があります。
特定の目標に応じてビジターを実装する方法は複数ありますが、一般的な考え方は、階層内の各ノードがビジターオブジェクトを受け入れることです。その実装は次のようになり、抽象的な親クラスに詰め込むことができます。
_public class Node {
public void accept(Visitor v) {
v.accept(this);
for (Node child : children) {
child.accept(v);
}
}
}
_
これにより、実行時にノードをどのように結び付けても、すべてのノードが処理されます。
あなたの訪問者は次のようになります:
_public interface Visitor {
accept(Node n);
}
_
訪問者のaccept(Node)
メソッドは、実際の作業が行われる場所です。ノードを検査し、条件付きで異なることを行う必要があります(ノードを無視することを含む)。
たとえば、次のことができる場合があります。
_Node root = ...;
// Print information on the hierarchy.
root.accept(new DebugVisitor());
// Does stuff with modules, ignores subcategories.
root.accept(new FrobnicateModulesVisitor());
// Eats vegetables, ignores animals and minerals.
root.accept(new EatYourVegetableVisitor());
_
各ビジターは自己完結型のクラスであり、他のビジターやノードと関係を混在させる必要なく、各操作のロジックが含まれています。
ネストの深いレベルは、returnステートメントを使用してチェーンできる小さな関数にアクションをリファクタリングする必要があることを示唆しています。複数の入力に同じメソッドを適用する必要がある場合は、Java 8.のfunction.apply()
を利用できます。
異なるアイテムがプロパティを共有しないと仮定すると、特定のメソッドセットを実装する必要がある interface を実装できます。レベルごとに1つのインターフェイスを作成し、それを各サブノードに対して拡張します。たとえば、Entity
、Phylum
、Species
のようにします。さらに、3つのエンティティのそれぞれに3つのクラスが必要です。
データは、オブジェクトインスタンスのプロパティとして保存できます。フラットなスナップショットを作成するには、function.apply()
を使用してデータ全体を反復処理します。