Designing the architecture of one project, I stopped at the MVP pattern - I was bribed by the ability to easily change ui, as well as the simplicity of the test coverage. All examples of MVP implementations that I found online were in C #. When implemented on Qt, a pair of unobvious moments arose, the solution of which was successfully found. The information collected is below.
MVP history
As follows from [1] and [2], the MVP design pattern is a modification of MVC applied for the first time in IBM in the 90s of the last century when working on the object-oriented operating system Taligent. Later MVP described Mike Pottel in detail.
To see what is the difference between MVP and MVC, you can see the corresponding paragraphs [3]:
MVC ,
MVPMVP implementation in Qt
In general, MVP is already used implicitly in Qt, as shown in [4]:
')

But this implementation of MVP has several disadvantages:
- unable to create multiple views for one representative (Presenter)
- It is impossible to use the Inversion of Control pattern described in [3] ( here ), because in this scheme, the View is automatically generated and cannot be inherited from the interface
The full implementation of MVP will look like this:

Hence the class diagram:

Consider each class:
- IView is an interface class that defines the methods and signals that a particular View must implement (see Inversion of Control in [3])
- Ui :: View - the class generated by the .ui file of the Qt-designer
- View is a specific view inherited from QWidget (or its descendant) and from IView. Contains GUI logic, i.e. the behavior of objects (for example, their animation)
- Model - domain data model (Domain Model); contains variables, flags, table models, etc.
- Presenter - representative; implements the interaction between the model and the view. It also interacts with the outside world through it, i.e. with the main application, with the server (for example, through the application services layer), etc.
At the stage of “drawing squares” everything is clear. Problems I had while trying to implement.
- When writing IView, you must declare signals. But for this IView must be inherited from QObject. Then, when trying to inherit View simultaneously from QWidget and IView, an error occurred. It turned out that a class cannot be inherited simultaneously from two QObject objects (even virtual inheritance did not help). How to get around this problem is shown in [5]: link . Thus, IView is not inherited from QObject and simply declares signals as completely virtual (abstract) methods in the public section. This is quite logical, since a signal is also a function, on call of which observers are notified through their slots (see the Observer pattern).
- Another problem arose when linking IView signals in the Presenter class. The fact is that Presenter contains a reference to IView (a specific View is added to the Presenter at runtime, but stored as IView — polymorphism is used). But for connecting signals and slots, the static
QObject::connect()
method is used, which accepts only heirs from QObject as objects, and IView is not one. But we know that any our View will be it. So the problem is solved by dynamic type conversion, as shown in [6]:
QObject * view_obj = dynamic_cast < QObject *>( m_view ); // m_view - IView
QObject :: connect ( view_obj , SIGNAL ( okActionTriggered ()),
this , SLOT ( processOkAction ()));
It is also worth noting that when implementing IView, only a header (.h) file is needed. If an .cpp file has been created for IView, it must be deleted, otherwise compilation problems may occur.
In principle, this information is enough to independently implement MVP in Qt, but I will give a simple example (only the implementation of MVP, without considering the interaction in the context of a real application).
A simple example of using MVP in Qt
In the archive 3 examples, this is the same application, but with additions in each example.
- MVP implementation
- Added the ability to create multiple views
- Full synchronization between views when data changes
All code is commented on in Doxygen-style, i.e. you can easily generate documentation using the Doxywizard.
Download examples
hereOut of scope
Here is a list of interesting questions on the topic that are not included in the article:
- testing the modules of the resulting system
- implementing View as libraries (using QtPlugin) in the context of MVP
- QtDeclarative view implementation (QML) in the context of MVP
- transferring presentations to Presenter through a class factory (this way you can easily change styles)
Comments are welcome any information on these issues.
Sources
- http://www.rsdn.ru/article/patterns/generic-mvc2.xml
- http://en.wikipedia.org/wiki/Model-view-presenter
- http://www.rsdn.ru/article/patterns/ModelViewPresenter.xml
- http://thesmithfam.org/blog/2009/09/27/model-view-presenter-and-qt/
- http://doc.trolltech.com/qq/qq15-academic.html
- http://developer.qt.nokia.com/forums/viewthread/284