The facts:
- I have two predominant classes: Manager and Specialist.
- There are several different types of Specialists.
- Specialists often require the help of other Specialists in order to get their job done.
- The Manager knows all of the Specialists, and initially each Specialist knows only their Manager. (This is the problem.)
- At runtime, the Manager creates and stores a list of Specialists. Then the Manager iterates through the list and asks each Specialist to initialize. During their initialization, each Specialist asks the Manager to supply them with other Specialists that fulfill some description. Once this is complete, the Manager then goes into a loop during which the Specialists are asked sequentially to perform their specialized task.
To me it seems that this is a decent pattern, but since a Manager has a list of Specialists and a Specialist has a Manager I'开发者_Go百科m getting circular dependency problems.
Is this a case where I should somehow forward declare the existence of one class from another? (If so, how?) Or should I use some design pattern to fix this problem? (If so what?) Also... I though the pattern itself was pretty o.k. so I wouldn't mind someone helping me understand why this is a bad thing.
In both cases, forward declare the other class:
Manager.h
class Specialist;
class Manager
{
std::list<Specialist*> m_specialists;
};
Specialist.h
class Manager;
class Specialist
{
Manager* m_myManager;
};
The only time you need to bring in the header file for a class is when you need to use a member function or variable within that class, or need to use the class as a value type etc. When you only need a pointer or reference to a class, a forward declaration will suffice.
Note that forward declarations aren't just for solving circular dependencies. You should use forward declarations wherever possible. They are always preferable to including an extra header file if it is at all viable.
It's a matter of taste, but forward declaration often is a good alternative to includes in header files even without circular dependencies. (I don't want to raise a discussion on that in this place.) So, here is an example on how to apply forward declarations for your problem:
In Manager.h:
// Forward declaration:
class Specialist;
// Class declaration:
class Manager
{
// Manager declarations go here.
// Only pointers or references to
// the Specialist class are used.
};
In Manager.cpp:
#include "Manager.h"
#include "Specialist.h"
// Manager definitions/implementations
// using the Specialist class go here.
// Full Specialist functionality can be used.
In Specialist.h:
// Forward declaration:
class Manager;
// Class declaration:
class Specialist
{
// Specialist declarations go here.
// Only pointers or references to
// the Manager class are used.
};
In Specialist.cpp:
#include "Specialist.h"
#include "Manager.h"
// Specialist definitions/implementations
// using the Manager class go here.
// Full Manager functionality can be used.
One option is to forward declare one of the people, as you suggest:
struct specialist;
struct manager
{
std::vector<std::shared_ptr<specialist> > subordinates_;
};
struct specialist
{
std::weak_ptr<manager> boss_;
};
However, if you end up having more of a tree-structure (where you have multiple layers of management, a person
base class would also work:
struct person
{
virtual ~person() { }
std::weak_ptr<person> boss_;
std::vector<std::shared_ptr<person> > subordinates_;
};
You can then derive specific classes for different types of people in the hierarchy. Whether or not you need this depends on how exactly you intend to use the classes.
If your implementation doesn't support std::shared_ptr
, it may support std::tr1::shared_ptr
or you can use boost::shared_ptr
.
this is normal stuff. You just need
class Manager;
in the specialist header and
class Specialist;
in the manager header
if you are using shared_ptrs you might find shared_from_this useful. (Not for looping but because it sounds like you will need it anyway)
While everyone else is answering the core question I thought I'd point this out.
At runtime, the Manager creates and stores a list of Specialists. Then the Manager iterates through the list and asks each Specialist to initialize. During their initialization, each Specialist asks the Manager to supply them with other Specialists that fulfill some description. Once this is complete, the Manager then goes into a loop during which the Specialists are asked sequentially to perform their specialized task.
I just want to point out that this needs to be a two-step process. How can the manager tell specialist 1 what specialists exist for task B if the manager only knows about one specialist so far? So you need:
1) manager goes through list of specialists and asks them to identify themselves.
2) manager goes through list of specialists and asks them what specialties they need access to, telling them who can fulfill their requirements.
3) manager goes though list of specialists and tells them to perform their actions.
精彩评论