Design Patterns and Frameworks

1. Introduction:

Design Patterns is the paradigm constantly discussed, not only by people trying to apply them as solutions to the programming problems they face but also by those, who are their eager opponents. No wonders a few other SAPM blog posts were devoted to that topic. And yet, I think I have some additional information I could share about them.

2. Summary:

This article introduces unfamiliar reader to the software Design Patterns and the advantages, as well as problems that they may relate to, when big projects are concerned. I also stated reasons, why in my opinion some of the flaws of Design Patterns may be solved with use of Software Frameworks, and how they help their users to comprehend Pattern Paradigm. In the last part, I shortly presented the Qt/C++ programming framework and described how some basic design patterns were used in its architecture and what implications it has on the client code of that library.

3. Background:

Design patterns are the solutions to reoccurring software design problems that engineers are facing in their projects. These are the techniques that have proven themselves in many different contexts and help to write code that is much more reusable. They are recorded in various catalogs (e.g. [1], [2]) along with the description of context they are supposed to be used and list of advantages and consequences of their applications. There are many benefits drawn from knowing and using design patterns [3]:

they can reduce development time as these solutions are given and widely used;

solutions are tested in a number of implementations, thus the design based on them is very robust;

they are very important in a large-scale projects, since they enhance documentation and facilitate communication among team members.

Apart from these, also inexperienced programmers may benefit from reading the patterns by developing good design skills and being prevented from “reinventing the wheel”.

Although all the good that design patterns bring, there are potential pitfalls of using them. Among the problem are steep learning curve, temptation of their abusement ([4]) by novice programmers or additional effort in design modification in order to take them into account. Also, they are not a piece of code that can be just used in an application being developed, but the abstractions that yet are to be implemented. What is more, as stated in a lecture – they may be an indicator of a “language smell” [5], the development language missing some features. And Design Patterns add to the code duplication! So what can we do then? Are these a real problems? In my opinion design patterns are the right tool to be exploited in software projects, especially large ones. However, I also think that some of the aforementioned drawbacks may be easily overcome with use of appropriate software frameworks which incorporate ideas of Design Patterns themselves.

4. Frameworks:

“A framework is a reusable design of all or part of a system that is represented by a set of abstract classes and the way their instances interact” [6]. It is a form of design reuse, provided by third parties in order to facilitate application development. Physically, it is a set of modules or libraries that extend functionality of used language. To be reusable, it usually implements design patterns and forces developer to think in terms of these paradigms. If a programming team uses this kind of framework, many issues of the design patterns are getting solved by themselves.

Firstly, I need to defend the programming languages capabilities. If the framework may be used in a given language, it means it intrinsically supports possibility of being facilitated with reusable solution. Thus, they are not susceptible to the “language smell” phenomenon. This is a case, for instance with a C++ language. C++ is said to be much more difficult than Java, which has much more design patterns already embedded. However when used with e.g. Qt ([7]) framework, it gets the same easiness of use. It could get even more useful than other languages if the framework is especially designed for a problem that application is to solve – for instance communication applications will benefit much more from patterns used in ACE ([8]).

Additionally, when using frameworks, it is much easier for developer to write bug free and higher quality code. It so, since they only have to focus on development of concrete solutions instead of abstractions and application internal skeletons. Not to be forgotten, the most popular frameworks tend to be used by thousands of people, thus it’s highly probable their bugs has been already spotted and fixed.

Thirdly, using established frameworks, help to get the use of design patterns right. The frameworks themselves tend to be documented well, which results in developers having better understanding on what is going on. Also, they have to implement client code only. That means, they are freed from making some of the design decisions and are forced by the framework to structure their components correctly.

Last but not least, open source frameworks give great opportunity to learn how to implement design patterns correctly in a real world. Even though such implementations are provided in the design patterns catalogs (e.g. [2]), they are considered there in isolation to everything else. In life, we sometimes have to trade single responsibility rule or take into account some other external factors. The source code of such programs is the best way to see, how top developers deal with such issues. This is one of the reasons, why I want to present the reader to the Qt Framework.

5. Qt Framework and its Design Patterns:

Qt Project [7] is a cross platform framework originally designed for C++ developers, which eventually supported also CSS(-like), QML and JavaScript languages. The project is constantly being developed and maintained for more than 18. Although at the beginning it was significantly refactored few time, the current release is rather stable. It is a mature and very well engineered project, which follows many of the established design patterns (more than 20, [15]). Of course, the library not only exposes the patterns to the client code, but extensively uses them by itself. This gives a proof by itself for how crucial design patterns to the solid design are. I suppose that quick overview over the design patterns used in Qt may be beneficial for some readers and get them engaged and encouraged to explore the topic in more detail on their own.

5.1 Strategy Pattern:

One of the exemplary usages of the strategy pattern (algorithm encapsulated into an object) in Qt is QValidator. This is an abstract class, that provides validation of the text input with QValidator::validate(…) method (also enables fixation of input, to make class more general with QValidator::fixup(…)). The context object (be it a line edit, a spin box or other), which uses the validator depends on its interface and for every input change, checks if it’s valid and takes appropriate action (e.g. if the integer value is expected, however arbitrary text is given, its background goes red). If there is no appropriate validator available to meet ones demands, they have to inherit QValidator and overwrite its two abstract methods.

Fig. 1. QLinedEdit with QValidators class diagram.

The solution is really nice, since the validation code may be reused in every class that requires textual input. And it is much more compact than either creating subclasses of QLineEdit (and each input widget) that validate input or registering validation object on text change events (as is done e.g. in Java Swing library).

5.2 Lightweight with Proxy:

Some of the Qt classes (like QVector, QList, QMap or QDomNode) implement Proxy pattern. It means, they don’t contain explicitly the data that they are supposed to have (e.g. array of stored elements in vector). Instead they consist of a pointer to a shared data block that contains a reference count and the data. The classes take care of housekeeping such as modifying the counter depending on how many classes have access to the data. Copying of data occures lazily (so called copy-on-write), when one of the instances is about to modify it. Such approach has few benefits over the traditional explicitly shared data. First of all, the objects are lightweight and making their copies is fast because it only involves copying the counter. Secondly, if most of them is used in read-only mode, no additional memory is to be used, no matter how many copies are done (apart from the memory for pointers). It also saves programmers from choices if they should pass and return instances by reference or value (with unnoticeable performance penalty).
If it comes to the programmer, he doesn’t have to be aware of the copy nuances. However, if he also wants to have such a behaviour in his own classes, Qt encourages him to do so by inheriting the QSharedData and referencing it with QSharedDataPointer or QExplicitlySharedDataPointer.
When discussing the Proxy pattern, it’s worth noticing Qt has its own smart pointer classes, which may help handling pointer. Among those there are QPointer (which is a guarded pointer), QSharedPointer (reference counting pointer), QWeakPointer (automatic weak reference to the pointer). Using smart pointer classes prevent from memory leaks and handling dangling pointers.

5.3 Observer pattern:

One of the big advantages of Qt over the other C++ frameworks is easiness of realising communication between objects (inherted from QObjects) – their signals and slots mechanism. The mechanism allows for type-safety and loose coupling between the callee and caller, unlike in standard callback scenario. It is realised with additional meta-data structure added to objects at the compilation time. However at the end, everything comes down to the Observer pattern.

5.4 Composite and Template Method:

Like in many other GUI frameworks, Qt utilizes Composite Design Pattern to display its widgets (QWidget inherited classes) and handle user input events. The widgets are arranged in hierarchical structure (parent-children relationship), which reflects their z-order (depth on the screen).

Fig. 2. Composite class diagram in case of QWidgets.

As may be seen in the Fig. 2 presenting a class diagram, Qt Composite is a slightly different than the traditional one. There is no distinction between Leaf and Composite. It is because all the QWidgets are allowed to add children at any time.

When the screen is to be redrawn, appropriate event (QEvent) is sent the parent and its QWidget::paintEvent(…) method (Template Method) invoked. Then the event is propagated down to the children.

When the mouse click event (or any other user input event) is concerned, it’s first dispatched to the top-most children and appropriate QWidget::mouse*Event(…) method invoked. If it’s handled by the method (QEvent::accept()), no further actions are taken. Otherwise, the event is propagated up towards the parent, on each hierarchy level calling widgets that might be interested in it (click occurred in their bounding rectangle).

Fig. 3. Example scenario of click event.

Fig. 4. Object diagram for example setup.

Fig. 5. Sequence diagram for a given scenario.

To visualize theses steps, let’s assume scenario of generation of mouse click event, as in the Fig. 3. Keep notice, the button is disabled, thus it will not be interested in the event. Object diagram for this setup is presented in Fig. 4. Simplified sequence diagram for scenario of message dispatching shows Fig. 4. First, qApp sends event method to the button. It doesn’t accepts the event, thus qApp tries its parent, which is QTabWidget tab.

6. Summary:

In my opinion, Design Patterns are very useful paradigm. They are a set of tools, which if used wisely may pay-off, especially when large programming projects are concerned. Undeniably, many inexperienced software developers may find them to be a great source of knowledge, to improve their design skills. However, they are no silver bullet and may be over- or misused leading to degradation of a project. Software engineers need to be careful when applying them – that means they have to consider all the advantages and trade-offs that pattern catalog mentions about them. This is a skill, which still requires an experience. However, if developer has possibility to use programming frameworks as Qt (or ACE, .NET, Java), it is much easier for him to make design decisions and start journey with design patterns.