lundi 17 juillet 2017

access non-static field of another class (system) as if it is my own field - elegantly

How to enable a system (SystemB1) to access a field of another system (SystemA::sub) as if it is its own field?

  • SystemA is a utility system with its own field Sub* sub.
  • SystemB1 - SystemB5 are systems that want to access SystemA::sub easily.
  • There are other systems, but it is not related to SystemA or any SystemB. (not shown)

Here is a working MCVE.

class SystemA;
class SystemB1;
class Core{
    public:
    SystemA* systemA=nullptr;
    SystemB1* systemB1=nullptr;
    //SystemB2,B3,B4,B5
};
//"SystemA.h"
class Sub1{
    public: void f(){std::cout<<"OK"<<std::endl;}
    //has 10-20 function
};
class SystemA : public Core{
    public: Sub1* sub1=new Sub1();
    //has 5-10 subsystems (Sub1 Sub2 Sub3 ...)
};
//"SystemB1.h"
class SystemB1 : public Core{
    public: void fB1();
};
//"SystemB1.cpp" , include "SystemA.h"
void SystemB1::fB1(){
    systemA->sub1->f(); //<--- Can it be more concise like `sub->f()` ?
}

Note :- (just in case it is related)

  • In real case, it uses service locator pattern (1 system ~ 1 service) and Sub1* sub1 is not a pointer but has operator->().
  • In real case, Sub1 is an ugly template type e.g. Sub<std::unordered_map<EnemyShip,Turret>>. Thus the most convenient way to refer to type of sub1 (if needed) is to use decltype.

Question

Are there any design pattern / C++ magic (except macro) to abbreviate systemA->sub1->f(); to something shorter like sub1->f();?

Sorry if it seems to be a very trivial question.
I want to improve my skill and productivity - every little thing can help.

My poor solution

The only solution I found is to create a base class for SystemB1,B2,... named SystemB.

class SystemB : public Core{
    public: Sub1* sub1; Sub2* sub2;  ...          (solution 1)
    //or alternative ....
    public: Sub1* getSub1();  Sub2* getSub2(); ...(solution 2)
    //^ e.g. return systemA->sub1
};

Then, SystemB1,B2... will be able to call sub1->f1() or getSub1()->f1() directly.

Disadvantage:

  • Whenever I add a new subX to SystemA :-

    • (Solution 1) I have to create a new field SystemB::subX and set it with a correct pointer.
    • (Solution 2) I have to add SystemB::getSubX() with correct implementation.
  • Whenever I change type of sub e.g. from Sub<std::unordered_map<EnemyShip,Turret>> to Sub<std::unordered_map<EnemyShip,Tracker>> in SystemA :-

    • I have to also change type of field or return type of function in SystemB OR use decltype(SystemA::sub1) (but it requires SystemB.h to #include SystemA.h)

These may cause some maintainability problem.

Aucun commentaire:

Enregistrer un commentaire