vendredi 16 avril 2021

Design pattern for a class where setters are callable only by a library

I'm developing a library in Qt.

I want to define a class where all the data are encapsulated, the user can call only the getters, the setters will be used by the library to update the class values.

I thought of this solution:

First export the class with public getters, private signals, and virtual protected setters.

#include <QObject>

class __declspec(dllexport) Motor : public QObject
{
   Q_OBJECT;
   Q_PROPERTY(int speed READ speed NOTIFY speedChanged)

public:
   explicit Motor(QObject *parent = nullptr) :
      QObject(parent),
      m_speed(0)
   {}

   inline speed() const { return m_speed; }

signals:
    void speedChanged(int speed, QPrivateSignal);

protected:
    virtual void setSpeed(const int speed) { Q_UNUSED(speed); }

protected:
   int m_speed;
};

After define (and not export) a "private like" class that derive the previous one and override the setters:

#include "Motor.h"

class MotorPrivate : public Motor
{
public:
   explicit MotorPrivate(QObject *parent = nullptr) :
      Motor(parent)
   {}

   inline void setSpeed(const int speed) override {
      if(m_speed == speed)
         return;
      m_speed = speed;
      emit speedChanged(speed, {});
   }
};

Now the final user can create the main class, pass it as a pointer to a library class, and after read the updated values.

#include <Motor.h>

int main {
   Motor *motor(new Motor());
   //motor->setSpeed(100); Give an error because is protected

   NetworkManager *nm(new NetworkManager())
   nm->setData(motor);
   nm->updateData();

   std::cout << "Motor speed: " << motor->speed();
   return 0;
}

Where the network manager class is defined in the library like

#include "MotorPrivate.h"

class __declspec(dllexport) NetworkManager : public QObject
{
   Q_OBJECT

public:
   explicit NetworkManager(QObject *parent = nullptr) : QObject(parent)
   {}

   void setData(Motor *motor) {
       if(motor)
          u_motor = static_cast<MotorPrivate *>(motor)
   }

   void updateData() {
      if(u_motor)
         u_motor->setSpeed(100);
   }

private:
   MotorPrivate *u_motor;
};

My questions are?

  • Is this a good design for my purpose?
  • Reading online seems that the compile will ignore the inline of the setter because when I call the function, the variable is not local but a derived reference. It's true? So there isn't any reason to inline all the setters?

Aucun commentaire:

Enregistrer un commentaire