I got myself into a circular dependency between two classes, and I'm trying to come up with a clean solution.
Here's the basic structure:
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 */ }
}
The ContainerManager is exposed as a WCF service: the external point through which clients can create Items and Containers. The ResourceManager needs to be aware of new Items that are created. It does background processing, and occasionally it requires information from the Item's Container.
Now, the Container needs to have the ResourceManager (to call ReportNewItem), which will be passed from the ContainerManager. The ResourceManager requires information from the Container, which it can only obtain using the ContainerManager. This creates a circular dependency.
I would prefer to initialize objects with interfaces (rather than concrete objects) so that I can later create mock objects for unit-tests (e.g. create a mock ResourceManager), but I'm still left with the problem that the CM requires an RM in its ctor, and the RM requires a CM in its ctor.
Obviously, this can't work, so I'm trying to come up with creative solutions. So far I have:
1) Pass to ReportNewItem the Container to be used, and have the ResourceManager use it directly. This is a pain because the ResourceManager persistently stores the ItemIDs it is aware of. This means that when initializing the ResourceManager after, say, a crash, I would have to re-provide it with all the Containers it needs.
2) Initialize either the CM or the RM in two phases: e.g.: RM = new RM(); CM = new CM(RM); RM.SetCM(CM); But this is ugly, I think.
3) Make ResourceManager a member of ContainerManager. Thus the CM can construct the RM with "this". This will work, but will be a pain during testing when I will want to create an RM mock.
4) Initialize CM with an IResourceManagerFactory. Have CM call Factory.Create(this), which will initialize the RM using "this", and then store the result. For testing, I can create a mock factory which will return a mock RM. I think this will be a good solution, but it's a bit awkward creating a factory just for this.
5) Break the ResourceManager logic into Container-specific logic, and have a distinct instance in each Container. Unfortunately, the logic really is cross-Container.
I think the "correct" way is to pull out some code into a third class that both CM and RM will depend on, but I can't come up with an elegant way of doing that. I came up with either encapsulating the "reported items" logic, or encapsulating the Component information logic, neither of which seems right.
Any insights or suggestions would be greatly appreciated.