Design patterns were introduced to the software community in the book Design Patterns, by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides (colloquially known as the “gang of four”). Over their years of developing software, these authors found certain patterns that can be helpful on building software applications.
The analogy of these patterns is just as architects designing houses and buildings can develop templates for where a bathroom should be located or how a kitchen should be configured. Having those templates or design patterns means that they can design better buildings more quickly. The same applies to software. Design patterns are the solution to the problems that arise frequently while software is being developed. They are like blueprints that can be customised to solve a problem, a template for how to solve it in many similar situations.
Pattern vs Algorithm
Usually patterns are confused with algorithms because both concepts provide a typical solution to a given problem. The algorithm is an effective way of expressing a finite list of well-defined instructions for calculating a function, it determines a series of actions to achieve a certain goal.
On the other hand, a pattern is more of a disciplined description for solving the problem. A pattern is not a specific part of a code. Programmers can follow the principles of the pattern and implement a solution that fits the reality of the program or software for which they are working. The code of the same pattern applied to two different programs may be considerably different.
An analogy to understand the difference between patterns and algorithms is that of a cooking recipe. Both concepts aim to solve the problem. But while an algorithm provides an almost exact solution, the pattern defines only some structure features and leaves the way of the implementation in the hands of the programmer.
What does the pattern consist of?
Most patterns are described very formally, so people can reproduce them in many contexts. A UI design pattern usually consists of the following elements:
- Intent of the pattern briefly describes both the problem and the solution.
- Motivation explains the problem further, as well as the solution that the pattern makes possible.
- Structure of the solution shows the various parts of the pattern and how they are related.
- Code example in a popular programming language makes it easier to grasp the idea behind the pattern.
Why should I learn patterns?
There are cases that a developer manages to do his job without possessing any skill or knowledge about design patterns. Many of us passed from that stage. There are also cases when a developer can implement one or more patterns without his/her knowledge. Also, the time needed to learn these design patterns from scratch is considerable, so it is reasonable to question whether teaching them is worthwhile.
If you can find a tool that already focuses on your problem, while eliminating some of the hard work, then it is apparently advantageous to use it. Design patterns are a toolkit that has been proven and tested to deliver solutions to the most common software design problems.
Although while working as developers some of us may have problems that cannot be solved by using any design pattern, the knowledge gained from studying them is always useful. This is because we learn how to face and manage situations in a variety of problems. The usage of these patterns provides solutions for specific design problems which are more flexible, elegant, and reusable.
Some problems solved from design patterns
Below is a couple of problems that can be handled through the usage of design patterns:
- Designing appropriate parts – Some complex part of an application might be decomposable into a system of parts (e.g. objects, modules, etc.). This is difficult because of many factors, like for example a particular part should be flexible, reusable, address future problems etc. Consider a scenario where an architect designs a bad software and how costly that can be for the organization in future. Also design patterns help in identifying the problems and create entities that can capture them (e.g. objects).
- Determining parts’ levels – Parts can vary in size. They can represent anything from a piece of hardware to the complete application. So how do we decide what a part should be? Design patterns can solve that too. Every function declared in a part specifies its name, parameters, and its return value. This is known as the function’s signature. The set of the signatures of all the functions defined in a part is called the interface of that part. A part’s interface describes the complete set of requests that can be sent to that part. It can be seen as the set of functions it can perform and states it can be in. There are several design patterns which will be covered in future posts.
Classification of patterns
Design patterns differ by their complexity, level of detail and scale of applicability to the system being designed. They are mostly categorized by their purpose. The main groups of patterns are:
- Creational patterns. They provide part-creation mechanisms that increase flexibility and reuse of existing code.
- Structural patterns. They explain how to assemble parts into larger structures, while keeping them flexible and efficient.
- Behavioural patterns. They take care of effective communication and the assignment of responsibilities between parts.
Software development has been constantly improved with new concepts, different methodologies and libraries of high quality. Despite all these improvements, we cannot prevent further changes in software development. There will be always a change request that could ruin a planned design. Adapter is a design pattern that serves in managing changes during development. In this article we are going to explore the usage of this pattern in software applications and its benefits.
Adapter pattern eliminates some common concerns of adapting changes to existing functionality as well as adding new functionality. Any class can work smoothly, as long as the Adapter solves the issue that all classes must implement exactly every method defined by the shared interface. Regarding the practical side, the adapter can be defined as an interface that helps integrate incompatible components. Below is a diagram of how adapter pattern works.
Clients call the methods of the Adapter through the Interface, then the Adapter calls the methods of the Server and if needed converts them to the input expected from the Server. One example of when to use this design pattern is when you have some client classes and they need to call some methods of a server class. There is the possibility that in the future this class might change the method that the client classes call. The idea is to eliminate the need for the developer to go all over the clients’ code to make the proper changes. Thus, a different way is required for the clients’ code not to break, and the adapter pattern provides one.
To make an illustration, consider a library (Server) that creates interactive graphs. Let’s assume that the Server provides three methods to do its work. One is for drawing a block, another for coloring it and the last for creating the links which connect the blocks to each other. These methods would be used throughout the application. If we are in the situation where the Server changes one of its methods, what we can do is to have an intermediate class which will play the role of the adapter. This will have a private instance of the Server class. We create a constructor that will take a Server object and save it.
Next, we need to implement an interface called Graph, which the client classes expect to work with and delegate to the adapter the job of making other classes compatible with this interface. This interface will be implemented by the adapter and used by the client classes. Lastly, we create an instance of a client object.
To understand the central concept of the adapter pattern, let’s change one of the methods of the Server, by renaming it from drawBlock to createBlock. We want that change in the Server to not break the clients’ code. The only change that needs to take place is inside the Adapter class, by renaming the call of drawBlock to createBlock. The same applies with any other method.
Below is the example code of the classes in php, along with short descriptions.
This is the Server (or the Adaptee). The Adapter receives method calls from the objects that use the Graph interface and translates them to the right methods defined in the Server.
This is the Interface. This is what the clients expect to work with. It is the Adapter’s job to make other classes compatible with this one.
ClientClass implements Graph. The Adapter’s job is to make classes with different methods from the Server to work through the Graph interface.
The Adapter must provide translations for the methods defined in Graph. It does this by containing an instance of the Adaptee (Server). All calls to Graph methods are properly translated and passed to the Server.
Who develops the Adapter Class?
When we are in need of an adapter, we can either create it ourselves or ask a vendor to provide it. It depends on the situation and type of the project we are working on. If we are developing applications by using a variety of third-party libraries, then we will be responsible for creating adapters to facilitate the change from one library to another. On the other hand, if the vendor of the library changes it, then they should provide an adapter as well.
In this post we had a look at the Adapter design pattern and tried to explain the effective use of it through a practical example. This series of posts will be extended with more design patterns, helping developers to grasp the corresponding concepts and giving a good idea of how they are used and implemented in code.