views:

58

answers:

3

Hi, I certainly don't know how to title this question, sorry.

I'm having some problems to design the following system.

I need a class which will make some work, but this work can be done in a bunch of different ways, say that this work will be made through "drivers".

These drivers can have different interfaces and because of that I need to build a wrapper for each driver.

So I got (or I need) this:

       Me --->    MainClass   ---->    Wrapper ---->  Drivers

MainClass is the class I will touch and will call the drivers methods through different wrappers.

Here an example of usage:

MainClass worker;
worker.set_driver("driver_0");
worker.start_process();      //Start process calls a wrapper method which calls a driver's method.

To achieve this I made an interface class:

class Driver_Interface : public QObject
{
     Q_OBJECT
 public:
   Driver_Interface(QObject* parent=0) : QObject(parent){}
   virtual bool open()=0;
   virtual bool close()=0;
   virtual bool write()=0;
   virtual bool set_config()=0;
};

A driver wrapper has this shape:

class Driver0 : public Driver_Interface
{
Q_OBJECT
public:
    Driver0( QObject* parent=0);
    Driver0();

    bool open();
    bool close();
    bool write();
    bool set_config();
};

Finally here comes the conflicting point, defining the MainClass: I would like to avoid to create one member for each wrapper, so I tried this, and right now compiler doesn't complains:

class MainClass
{
public:
    MainClass();
    ~MainClass();
    void init();
    void set_driver( const QString& );
    void start_process();
protected:
    QString driver_str;
    Driver_Interface* driver;  //!<--- Here Here!!!
};

When setting the driver chosen, I do this:

if( driver_str.compare("driver_0")==0 )
     this->driver = new Driver_0();
  1. Is this a valid C++ configuration or will I have problems sooner or later? Basically, what worries me is the creation of the driver of a different type from Driver_Interface, I'm seeing that it casts automatically and no one complains...
  2. Actually I have some problems now compiling, the infamous vtables not defined in Driver_0... does this have some relation with what I want to achieve? UPDATED: I fixed this by deleting the *Driver_Interface* constructor.
+3  A: 

To me your basic idea seems to be fine. I would consider separating the creation of drivers into a factory (or at least a factory method) though.

Péter Török
the new Driver_0() is made inside "MainClass", so it is encapsulated. Is this what you mean?
clinisbut
@clinisbut, as the first step, yes. Depending on the situation, I might prefer migrating the creation code out of `MainClass`, to eliminate dependencies to concrete Driver subclasses. It may not be a problem if you only have a few fixed subclasses, and creating them is simple. But if you have many, and/or creating them is complicated, the creation code clutters `MainClass`. Or if you expect to add new ones, without this separation you would need to recompile MainClass every time a driver is added or removed.
Péter Török
+1 for comment about maintainability
Steve Townsend
+1  A: 

This seems reasonable to me. Having a FactoryMethod or class (AbstractFactory) that creates an object of the required concrete subclass based on some config value is a common pattern.

You could consider having the MainClass implement something like

DriverInterface* createDriver(const string& driverType)

instead of encapsulating the resulting concrete DriverInterface subclass in MainClass. But if you only ever want one concrete DriverInterface instance, the above looks fine.

Steve Townsend
A: 

I would pass "driver_0" to the constructor, and call MainClass::set_driver from there. You can then make MainClass::set_driver private unless you need to change drivers.

Patrick