mercredi 15 août 2018

Object with multiple inheritance sharing one resource - looking for good design pattern

Hope this has not been answered before, I found it very hard to find a snappy description of my problem.

I'm about to write a C++ API that should compile on microcontroller as well as on PC targets which abstracts communication with some hardware device. The operation modes of the device and with that the parameters to control might change at runtime while the connection stays the same. The connection is managed by a separate class, to which my base class instance has a protected reference. A basic device looks like that (simplified example):

class DeviceBase
{
public:
    void setOnOffState (bool onOff);
    bool getOnOffState();
protected:
    DeviceBase (Connection& c);
    Connection& connection;
}

DeviceBase::DeciveBase (Connection& c) : connection (c) {};
void DeviceBase::setOnOffState (bool onOff) {connection.sendParameter (/* Parameter number for onOff */, onOff); };
bool DeviceBase::getOnPffState() {return connection.requestParameter (/* Parameter number for onOff */); };

Now there are some generic device types which all share a basic parameter set. Let's say there is generic type 1 which always has parameterA and parameterB and generic type 2 which always has parameterC and parameterD. So their implementation could look like this:

class GenericDeviceType1 : public DeviceBase
{
public:
    void setParameterA (int parameterA);
    int getParameterA();
    void setParameterB (char parameterB);
    char getParameterB();
protected:
    GenericDeviceType1 (Connection& c);
}

GenericDeviceType1::GenericDeviceType1 (Connection& c) : DeviceBase (c) {};
void GenericDeviceType1::setParameterA (int parameterA) {connection.sendParameter (/* Parameter number for parameterA */, parameterA); };
int  GenericDeviceType1::getParameterA() {return connection.requestParameter (/* Parameter number for parameterA */); };
//... and so on - I think you got the principle

But it gets even more complicated. There are specific flavors of each type. But some share some groups of parameters. Now what I'd ideally like to do is to build them up with multiple inheritance like this:

class DeviceType1ParameterSetX // a device with parameters E and F
{
public:
    void setParameterE (float parameterE);
    float getParameterE();
    void setParameterF (int parameterF);
    int getParameterF();
}

class DeviceType1ParameterSetY // a device with parameters G and H
{
public:
    void setParameterG (bool parameterG);
    bool getParameterG();
    void setParameterH (char parameterH);
    char getParameterH();
}

class DeviceType1ParameterSetZ // a device with parameters I and J
{
public:
    void setParameterI (int parameterI);
    int getParameterI();
    void setParameterJ (int parameterJ);
    int getParameterJ();
}

class SpecificDeviceType11 : public GenericDeviceType1,
                             public DeviceType1ParameterSetX,
                             public DeviceType1ParameterSetY
{
public:
    SpecificDeviceType11 (Connection &c);
    //...
}

class SpecificDeviceType12 : public GenericDeviceType1,
                             public DeviceType1ParameterSetX,
                             public DeviceType1ParameterSetZ
{
public:
    SpecificDeviceType12 (Connection &c);
    //...
}

Problem with this approach: The classes DeviceTypeNParameterSetM don't know anything about the connection, so implementing their setter and getter functions invoking the connection instance is not directly possible. However, I really would like to avoid making the connection member of the base class public to keep the api clean. I know that I could store a reference to the connection in each parameter set class, but that seems like a waste of memory to me, regarding the fact that this should be able run on a microcontroller with a small memory footprint and without the possibility of dynamic memory management. So ideally the memory footprint of each specific instance should be the same.

Now my question is: How could a solution resulting in a clean public API look like? I'm looking forward to some inspiration! As a side information: There will be some 150 different specific device flavors in the end, so I'd really like to keep it as organized and user-friendly as possible!

Aucun commentaire:

Enregistrer un commentaire