Abstract Factory extensible with plugin
-
I'm new to Qt (using Creator 3.2.1 (Based on Qt 5.3.2 (MSVC 2010, 32 bit)) and am trying to make a good implementation of an abstract factory so that it is extensible with plugins.
I found an interesting topic with the way I would like to implement the application on "Abstract Factory Step-by-Step Implementation in C++" ([http://www.codeproject.com/Articles/751869/Abstract�Factory�Step�by�Step�Implementation�in�Cp6/9](link url)), but this C++ example is in the C++ 11 coding and not intended for Qt. Also I can't judge if this is a good way of making the application extensible or if there is a better "Qt way" of doing this. I have searched through the Qt forum and read the "An Introduction to Design Patterns in C++ with Qt" book. Can someone point me to a good Qt example with extensible plugins?
-
You can use C++11 with Qt.
Qt provides support for plug-ins: http://doc.qt.io/qt-5/plugins-howto.html -
you can see the Plug & Paint Example
http://doc.qt.io/qt-5/qtwidgets-tools-plugandpaint-example.html -
Thanx for the quick response and information! I did try the plug and paint example, but this didn't compile correctly, thus I didn't check it out further. If this is a good way to program plugins, I will try to fix it to get a better understanding how it works and how I can implement something simular for my app.
By referencing topic [https://forum.qt.io/topic/64972/plugin-example-app-launch-problem-1-error-cannot-find-lpnp_basictools/21] (a big thank you to SGaist and Kofr!) and [http://doc.qt.io/qt-5/qmake-language.html]
For those interested in a fix for the plugandpaint app on windows, this is how I got it to work:
- Make directory "C:\Temp\plugandpaintplugins\basictools"
- Make directory "C:\Temp\plugandpaintplugins\extrafilters"
- Make directory "C:\Temp\plugandpaint"
- Copy directory "C:\Qt\Qt5.3.2\Examples\Qt-5.3\widgets\tools\plugandpaintplugins\basictools" to "C:\Temp\plugandpaintplugins\basictools"
Copy directory "C:\Qt\Qt5.3.2\Examples\Qt-5.3\widgets\tools\plugandpaintplugins\extrafilters" to "C:\Temp\plugandpaintplugins\extrafilters" - Copy directory "C:\Qt\Qt5.3.2\Examples\Qt-5.3\widgets\tools\plugandpaint" to "C:\Temp\plugandpaint"
- Delete contents of "C:\Temp\plugandpaint\plugins"
- Open Project "basictools.pro" and change following:
Delete line: "target.path = $$[QT_INSTALL_EXAMPLES]/widgets/tools/plugandpaint/plugins"
Add line: "target.path = C:/Temp/plugandpaint/plugins" - Clean, Run qmake, Build
- Open Project "extrafilters.pro" and change following:
Delete line: "target.path = $$[QT_INSTALL_EXAMPLES]/widgets/tools/plugandpaint/plugins"
Add line: "target.path = C:/Temp/plugandpaint/plugins" - Clean, Run qmake, Build
- Open Project "plugandpaint.pro" and change following:
Delete lines "#LIBS = -Lplugins -lpnp_basictools
if(!debug_and_release|build_pass):CONFIG(debug, debug|release) {
mac:LIBS = $$member(LIBS, 0) $$member(LIBS, 1)_debug
win32:LIBS = $$member(LIBS, 0) $$member(LIBS, 1)d}"
Add line "win32:CONFIG(release, debug|release): LIBS += $$PWD/plugins/pnp_basictools.lib"
Add line "else:win32:CONFIG(debug, debug|release): LIBS += $$PWD/plugins/pnp_basictoolsd.lib"
Delete line "target.path = $$[QT_INSTALL_EXAMPLES]/widgets/tools/plugandpaint"
Add line "target.path = C:/Temp/plugandpaint" - In file "mainwindow.cpp" under lines "#if defined(Q_OS_WIN)
if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release")
pluginsDir.cdUp();"
Add lines "pluginsDir.cdUp();
pluginsDir.cd("plugandpaint");" - Clean, Run qmake, Run
-
I've studied the plugandpaint example. I derive from the coding structure that its design pattern is a Factory Method instead of an Abstract Factory. I programmed code based on a which seems to me a good Abstract Factory example programmed in Qt that I found on:
https://github.com/hoowang/abstractFactoryExample (with a big thank you to coderHooge!)
Now I try to introduce concrete factory 'factory3' as a plugin, but this doesn't compile correctly giving linking errors like: "factory3.obj:-1: error: LNK2019: unresolved external symbol "public: __thiscall abstractFactory::abstractFactory(void)" (??0abstractFactory@@QAE@XZ) referenced in function "public: __thiscall Factory3::Factory3(void)" (??0Factory3@@QAE@XZ)"The source of my tryout code is in:
https://github.com/bokki/abstractFactoryPlugin
Am I trying to do something wrong? Can someone please help on this issue? -
Have tried different coding and I'm still struggling with this issue. It looks like my attempt at coding an abstract factory that is extensible with plugin is not possible with QtPlugin. Seems strange, because I gathered alot of information that it is a very good way of programming plugins like the COM objects has been done. Any other suggestions of correct implementation of QtPlugin is most wellcome!
-
@kshegunov
I would like to extend my application with plugins. I wanted to use the GoF abstract factory design pattern and be able to extend my application by adding more concrete factories as plugin. However I find that QtPlugin does not allow for this. Please check out my code at:
https://github.com/bokki/abstractFactoryPluginThanx in advance.
-
@bokki
Then the plug and paint example is the way to go. It boils down to this:- You create a plugin interface in your application that your plugins will have to implement. That will give you enough information for the plugin. The plugin implementation is the factory itself, so you can do something like this for example:
class MyPluginInterface { public: virtual QStringList features() const = 0; virtual QWidget * getSomeDialog() = 0; }; Q_DECLARE_INTERFACE(MyPluginInterface, "my.plugin.id.string")
And in your application you load the available plugins with
QPluginLoader
(usually somewhere in main/main window):QPluginLoader loader("/the/library/containing/the/plugin"); QObject * plugin = loader.instance(); if (plugin) { //< The plugin was loaded //< You can save the `plugin` var here for later (which is usually done) MyPluginInterface * interface = qobject_cast<MyPluginInterface *>(plugin); //< See if that plugin implements MyPluginInterface if (!interface) { //< It doesn't implement it, so you can skip or decide what to do } else { //< It does implement it, so you can show a dialog or call something from MyPluginInterface you need } }
- On the plugin side, you create a dynamic library (not qt plugin, but plain C++ dynamic library) in Creator or the IDE you're using. You include the header(s) that declare(s) the interfaces you want to implement. You derive from
QObject
and implement those interfaces:
class MyFirstPlugin : public QObject, public MyPluginInterface { Q_INTERFACES(MyPluginInterface) //< Tell Qt which interfaces this plugin implements Q_PLUGIN_METADATA(IID "my.first.plugin.id") //< Tell Qt to export the plugin with that IID //< Implement the pure virtual methods of MyPluginInterface here };
That's pretty much it. You build your plugin library and if found at the specified location it will be loaded when you run your application. See here for the full explanation and use the plug and paint example as a guide.
PS.
I wanted to use the GoF abstract factory design pattern and be able to extend my application by adding more concrete factories as plugin.
Everything is a pattern these days ... just apply common sense and follow the documentation, don't jump into design pattern, just because it's called that way. The plugin
QObject
is the (root) factory, so just provide the interface and create whatever object/factory you wish from there.Kind regards.
-
@kshegunov
Thanx for the information. I will try to write the code as you said, but as I said before, I am new to Qt and am using books, examples and info from you gurus to try and program the code correctly. The books recommend the abstract factory design pattern and the Qt example I found on:
https://github.com/hoowang/abstractFactoryExample, compiles and runs correctly. The next step i tried is to add to this code a factory3 using Qt plugin. In my view this should be possible. -
@bokki said:
The books recommend the abstract factory design pattern
Does it explain what an abstract factory design pattern is though? In my very simplistic example above
MyPluginInterface
is already a factory, why do you need more factories is beyond me, but let's assume it's necessary. So, then your interface will change to reflect that requirement:// This is a factory class SomeOtherFactory { public: virtual QWidget * createSomeWidget() const = 0; } // This interface is called an abstract factory, and for whatever reason it's a "design pattern" class MyAbstractFactory { public: virtual SomeOtherFactory * dialogFactory() const = 0; virtual SomeOtherFactory * menuFactory() const = 0; // And so on }
So here you go, changing
MyPluginInterface
toMyAbstractFactory
is exactly the design pattern you want.