dimanche 29 novembre 2015

Extending Class via Multiple Private Inheritance - Is this a thing?

I'm trying to encapsulate existing functionality in a wide swathe of classes so it can be uniformly modified (e.g. mutexed, optimized, logged, etc.) For some reason, I've gotten it into my head that (multiple) private inheritance is the way to go, but I can't find what led me to that conclusion.

The question is: what is the name for what I am trying to do, and where I can see it done right?

What I think this isn't:

  • Decorator: All the descriptions I see for this pattern wrap a class to provide extra methods as viewed from the outside. I want to provide functionality to the inside (extract existing as well as add additional.)
  • Interface: This is close, because the functionality has a well-defined interface (and one I would like to mock for testing.) But again this pattern deals with the view from the outside.

I'm also open to alternatives, but the jackpot here is finding an article on it written by someone much smarter than me (a la Alexandrescu, Meyers, Sutter, etc.)

Example code:

// Original code, this stuff is all over
class SprinkledFunctionality
{
  void doSomething()
  {
    ...
    int id = 42;
    Db* pDb = Db::getDbInstance(); // This should be a reference or have a ptr check IRL
    Thing* pThing = pDb->getAThing(id);
    ...
  }
}

// The desired functionality has been extracted into a method, so that's good
class ExtractedFunctionality
{
  void doSomething()
  {
    ...
    int id = 42;
    Thing* pThing = getAThing(id);
    ...
  }

protected:
  Thing* getAThing(int id)
  {
    Db* pDb = Db::getDbInstance();
    return pDb->getAThing(id);
  }
}

// What I'm trying to do, or want to emulate
class InheritedFunctionality : private DbAccessor
{
  void doSomething()
  {
    ...
    int id = 42;
    Thing* pThing = getAThing(id);
    ...
  }
}

// Now modifying this affects everyone who accesses the DB, which is even better
class DbAccessor
{
public:
  Thing* getAThing(int id)
  {
    // Mutexing the DB access here would save a lot of effort and can't be forgotten
    std::cout << "Getting thing #" << id << std::endl; // Logging is easier
    Db* pDb = Db::getDbInstance(); // This can now be a ptr check in one place instead of 100+
    return = pDb->getAThing(id);
  }
}

Aucun commentaire:

Enregistrer un commentaire