我把自己变成了两个类之间的循环依赖关系,我试图想出一个干净的解决方案。设计问题 - 解决对象之间的循环依赖关系
这里的基本结构:
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