私は 2 つのクラス間の循環依存関係に陥り、クリーンな解決策を考え出そうとしています。
基本的な構造は次のとおりです。
class ContainerManager {
Dictionary<ContainerID, Container> m_containers;
void CreateContainer() { ... }
void DoStuff(ContainerID containerID) { m_containers[containerID].DoStuff(); }
}
class Container {
private Dictionary<ItemID, Item> m_items;
void SetContainerResourceLimit(int limit) { ... }
void DoStuff() {
itemID = GenerateNewID();
item = new Item();
m_items[itemID] = item;
// Need to call ResourceManager.ReportNewItem(itemID);
}
}
class ResourceManager {
private List<ItemID> m_knownItems;
void ReportNewItem(ItemID itemID) { ... }
void PeriodicLogic() { /* need ResourceLimit from container of each item */ }
}
ContainerManager は WCF サービスとして公開されます。これは、クライアントがアイテムとコンテナーを作成できる外部ポイントです。ResourceManager は、作成された新しいアイテムを認識する必要があります。バックグラウンド処理を行い、時にはアイテムのコンテナからの情報を必要とします。
ここで、コンテナには、ContainerManager から渡される ResourceManager (ReportNewItem を呼び出すため) が必要です。ResourceManager は、ContainerManager を使用してのみ取得できるコンテナからの情報を必要とします。これにより、循環依存が作成されます。
後で単体テスト用のモック オブジェクトを作成できるように (具体的なオブジェクトではなく)、インターフェイスを使用してオブジェクトを初期化することをお勧めします (たとえば、モック ResourceManager を作成します)。 RM はその ctor に CM を必要とします。
明らかにこれではうまくいかないので、クリエイティブな解決策を考え出そうとしています。これまでのところ、私は持っています:
1) ReportNewItem に使用するコンテナを渡し、ResourceManager に直接使用させる。ResourceManager は認識している ItemID を永続的に保存するため、これは面倒です。これは、たとえばクラッシュ後に ResourceManager を初期化するときに、必要なすべてのコンテナーを再提供する必要があることを意味します。
2) CM または RM のいずれかを 2 つのフェーズで初期化します。例: RM = new RM(); CM = 新しい CM(RM); RM.SetCM(CM); しかし、これは醜いと思います。
3) ResourceManager を ContainerManager のメンバーにします。したがって、CM は「this」を使用して RM を構築できます。これは機能しますが、テスト中に RM モックを作成するときに苦労します。
4) IResourceManagerFactory で CM を初期化します。「this」を使用して RM を初期化する Factory.Create(this) を CM に呼び出してもらい、結果を保存します。テストのために、モック RM を返すモック ファクトリを作成できます。これは良い解決策になると思いますが、このためだけにファクトリを作成するのは少し面倒です。
5) ResourceManager ロジックをコンテナ固有のロジックに分割し、各コンテナに個別のインスタンスを作成します。残念ながら、ロジックは実際にはコンテナ間です。
「正しい」方法は、CM と RM の両方が依存する第 3 のクラスにコードを引き出すことだと思いますが、それを行うエレガントな方法を思いつくことはできません。「報告された項目」のロジックをカプセル化するか、コンポーネント情報ロジックをカプセル化するかのどちらかを思いつきましたが、どちらも正しくないようです。
洞察や提案をいただければ幸いです。