0

I want to write an application where I would delegate certain functionalities to 3rd party libraries. To make sure the code remains modular, I want to put these libraries behind an interface so I can swap out the underlying implementation when needed, or even use multiple different implementations simultaneously.

Specifically, I want to make a GUI application and use either Qt or wxWidgets to implement the GUI elements. Both have a basic window and a dialog that inherits from it, so intuitively my interface would look something like this:

class Window
{
    virtual void open() = 0;

    // ...
};

class Dialog : public Window
{
    virtual void open() override 
    { 
        // ... 
    }
    
    // ...
};

Qt implements these using QWidget and QDialog, while wxWidgets uses wxWindow and wxDialog respectively. So my implementation wrappers would look something like this:

class QtWindow : public Window
{
    // Uses QWidget internally
};

class QtDialog : public Dialog, public QtWindow
{
    // Uses QWidget internally
};

class wxWidgetsWindow : public Window
{
    // Uses wxWindow internally
};

class wxWidgetsDialog : public Dialog, public wxWidgetsWindow
{
    // Uses wxDialog internally
};

The main draw of using such a class hierarchy is that I can ensure that every implementation fits the same interface, i.e any change I make to Window or Dialog must then propagate to changes in the Qt and wxWidgets wrapper objects as well. The obvious downside is the diamond inheritance, which I could solve via virtual inheritance, but it just feels like bad design altogether.

Is there a design approach that would work better in the above scenario?

7
  • 2
    The typical approach for separating a GUI away from the rest of the logic (allowing your program to use multiple different GUIs) would be using Model-View-Controller or some other variation to build a GUI layer (Views) using your chosen framework, then using framework-agnostic Controllers to wire the GUI into the rest of the application. Also see softwareengineering.stackexchange.com/questions/tagged/… Commented Nov 30, 2021 at 5:37
  • Your question title is misleading, it is not about wrapping "multiple libraries" (which would most probably too broad to be answered here), it is about wrapping the UI framework (which requires a different approach than for other kind of libs). So let me fix this for you.
    – Doc Brown
    Commented Nov 30, 2021 at 6:25
  • @DocBrown It was the most straightforward example I could think of, though I did want to apply it for UI as well, so the title is more appropriate.
    – yah_nosh
    Commented Nov 30, 2021 at 11:12
  • @yah_nosh: there is no "one-size-fits-all" solution for wrapping libraries or frameworks, and when you just ask about an approach applicable for different types of libs, don't be astonished when the community closes the question with the "needs more focus" reason.
    – Doc Brown
    Commented Nov 30, 2021 at 12:02
  • @DocBrown Sorry I worded that wrong, I meant the edited title is more appropriate. Not disagreeing with you. In terms of a "general solution" I wanted to focus on frameworks that rely more on OOP, like in the examples I gave, just in case there is a good rule of thumb for separating interface and implementation. If it's very context-dependent, however, then I will focus my questions on specific frameworks. Thank you for your replies.
    – yah_nosh
    Commented Nov 30, 2021 at 12:16

1 Answer 1

6

You are almost on the right track.

For separating a UI framework like Qt or wxWidgets from the remaining application, it is neither sufficient nor scalable to encapsulate the basic window or widget classes of the framework once (like one could do this for simpler libraries). The UI elements will have to be executed within the event loops of their framework, one cannot change the implementation of each lib (so not just introduce some interfaces on the existing classes), and one usually wants to be able to use all the tooling which comes with each framework (like graphical designers, resource management tools etc).

To solve this, I would recommend to use the Model View Presenter architecture, as it was described by Michael Feathers in his article "The Humble Dialog Box". This works basically the way you started here, with a common interface or abstract class (like Window) for each window ("View"). To make this example clearer, let's call this class MyCustomView, so it becomes more apparent this is not a generic interface, but a specific one, different for each of the windows in your application.

MyCustomView will require a Qt implementation and a wxWidgets implementation. For example MyCustomQtWindow could be derived from QDialog and MyCustomView.

The framework independent logic is not put into a class derived from MyCustomView (like your Dialog example), but into a Presenter class, like MyCustomPresenter. The presenter gets a (smart) pointer or reference to a MyCustomView instance, and MyCustomView holds a pointer or reference to the presenter instance. Now all what remains is to develop commands for the presenter which can be called from the view classes (for example, from the event handlers), and to extend the interface MyCustomView (and its specific implementation), for each case where the presenter has to notify or manipulate the the view.

Note, in this architecture, MyCustomView and MyCustomPresenter can be put into a library which is not linked against Qt or wxWidgets - only the classes which implement MyCustomView need to be put into libs which are linked against those specfic framework libraries.

3
  • Thank you, this does sound like a good way to approach it. However, my example may have emphasized UI too much. In general, suppose I wanted to wrap any library where it's common practice to subclass a provided base class to implement custom behavior. In the above example, if a user wants a window with custom content and behavior, they would subclass Window (as it is commonly done in both Qt and wxWidgets). Would that require a MyCustomQtWindow parallel with MyCustomWindow?
    – yah_nosh
    Commented Nov 30, 2021 at 10:44
  • @yah_nosh: focussing only on one type of lib of framework is what keeps your question alive, if you have questions for other types frameworks, you better ask specificially for them. And to your question about subclassing: yep, that is exactly what I wrote above. MyCustomQtWindow will, however, only be responsible for the custom content. The custom behaviour should be implemented in MyCustomPresenter, as long as it is framework agnostic.
    – Doc Brown
    Commented Nov 30, 2021 at 12:12
  • 2
    Often it's better to wrap libraries through ownership rather than inheritance, which avoids the diamond, but at this point the question becomes too general to really answer
    – pjc50
    Commented Nov 30, 2021 at 12:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.