我把自己變成了兩個類之間的循環依賴關係,我試圖想出一個乾淨的解決方案。設計問題 - 解決對象之間的循環依賴關係
這裏的基本結構:
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需要知道創建的新項目。它做後臺處理,偶爾它需要來自Item的容器的信息。
現在,Container需要有ResourceManager(要調用ReportNewItem),它將從ContainerManager傳遞。 ResourceManager需要來自Container的信息,它只能使用ContainerManager獲取。這創建了一個循環依賴。我傾向於使用接口(而不是具體對象)初始化對象,以便稍後可以爲單元測試創建模擬對象(例如創建一個模擬的ResourceManager),但是我仍然留下了CM的問題RM需要RM,而RM需要CM的CM。
很明顯,這是行不通的,所以我試圖想出創造性的解決方案。到目前爲止,我有:
1)傳遞給ReportNewItem要使用的容器,並讓ResourceManager直接使用它。這是一個痛苦,因爲ResourceManager持久地存儲它所知道的ItemID。這意味着,在例如崩潰之後初始化ResourceManager時,我將不得不重新提供它所需的所有容器。 2)以兩個階段初始化CM或RM:例如:RM = new RM(); CM =新CM(RM); RM.SetCM(CM);但我認爲這很難看。
3)使ResourceManager成爲ContainerManager的成員。因此,CM可以用「this」構造RM。這將起作用,但在測試期間我會想創建一個RM模擬器時會很痛苦。
4)用IResourceManagerFactory初始化CM。讓CM調用Factory.Create(this),它將使用「this」初始化RM,然後存儲結果。爲了測試,我可以創建一個模擬工廠,它將返回一個模擬RM。我認爲這將是一個很好的解決方案,但爲此創建工廠有點尷尬。
5)將ResourceManager邏輯分解爲特定於Container的邏輯,並在每個Container中具有不同的實例。不幸的是,邏輯真的是跨容器。
我認爲「正確的」方法是將一些代碼放到CM和RM都依賴的第三類中,但我無法想出一個優雅的方法來實現這一點。我想出了封裝「報告的項目」邏輯,或封裝組件信息邏輯,這兩者似乎都沒錯。
任何見解或建議將不勝感激。
您是否考慮過使用'System.Collections.ObjectModel'命名空間中的'KeyedCollection'。它將幫助您簡化item和itemID或container和containerID之間的類層次結構。 –
ja72
2010-08-30 20:47:30
另外考慮使用事件而不是將函數調用鏈接到'DoStuff()'和'ReportNewItem()' – ja72 2010-08-30 20:51:26