简体   繁体   中英

C++ software design options, class relationships

Problem:

I have totally separate software managers (software entities), for example CCarManager, CTruckManager etc.. At some point I am creating new objects for example CCar. CCar must have relationships with various separate managers, for example, with CResourceManager, CTruckManager. What is the best way to link CCar with these managers?

Solutions:

  1. Have global software managers (Singleton or extern in header file) [Don't like globals]

  2. Use one global point and pass it to other obects eg CCar(CApplication), CApplication->TrukManager(), CApplication->CarManager()... [Doesn't seem nice, but can pass one pointer]

  3. Pass to CCar(CCarManager *pCarManager, CTruckManager *pTruckManager....) [Hard to extend]

  4. Use Observer pattern eg CCar.Attach(CCarManager), CCar.Attach(CTruckManager); [Easy to extend, but main focus become for dealing method calls, what parts are responsible for what etc., also lot of check's]

  5. Factory.

    class CCarFactory(CCarManager *pMngr) { CCar *CreateCar() { return CCar(m_pCarManager); } }

what are the other ways?

You can pass a reference to CResourceManager , CTruckManager , etc. in CCar 's constructor.

CCar(const CResourceManager& resourceMgr, const CTruckManager& truckMgr):
    _resourceMgr(resourceMgr), _truckMgr(truckMgr) {
    //relevant construtor code here
}

This way it's easy to test with mock implementations as well. It's hard to say without knowing what the 'Manager classes do.

IMHO, classes whose names end in 'Manager' are often either poorly named (which I've done more times than I can count), or poorly designed.

If the only reason you won't use the Singleton pattern is because you don't like it, I think you might want to reconsider your approach.

Singletons are a perfect pattern for what you're trying to acheive here. You have management classes that should only have one instance and require access from many other classes.

Its hard to say without some more specifications... If CCar requires special access to the manager methods (like internal variables/methods) or vice-versa, you can declare in CCar managers as friend, or CCar as friend in those manager classes.

simple example, mind the poor member names

class CCar
{
    int I;
public:
    friend class CManager;
    CCar(int i): I(i) {}

};

class CManager
{
    int D;
public:
    CManager(int i, CCar& car): D(i) 
    {
        car.I = 5;      // modify CCar instance internal member
    }

};

or vice versa if its the other way around.

If a CCar instance can have multiple CCarManagers, you could set up an array of pointers to 'link' those managers to an instance of CCar. Rather than having 3 different pManager arrays, having a Manager base class, and subclassing those managers to it, will let you store all references to managers in a single array.

class Manager // etc...

class CResourceManager : public Manager 

// in CCar
std::vector<Manager*> _mgrs;
// or if heap allocated
std::vector<std::shared_ptr<Manager>> _mgrs; // assuming multiple CCars can reference same manager instance

Another method could be to have a struct/class that can hold all manager references for a particular instance.

struct MgrRefs
{
    std::vector<CCarManager*> _pCarMgrs;
    std::vector<CResourceManager*> _pResMgrs;
    // etc....
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM