When we think about the software development routine, we can quickly identify that many times, the solution to a specific problem has identical characteristics, if not equal to that found in a previously developed project but the solution and the problem had not been documented. So, you are facing a similar problem, that was solved in the past, but there’s no record of how it was solved, making it extremely hard to reuse ideas and solutions. In this way, the occurrence of identical problems that are repeated in other contexts, consume more time and resources then they should, since the solutions were already explored before.
In this way, Design Pattern are great allies. A Design Pattern can be described as the recurring solution to a problem in a context, even if in different projects and areas. The key terms here are: context, problem and solution. One context concerns the environment, and the circumstances within which element exists. The problem is the undefined issue, something that needs to be investigated and resolved. It is usually tied to the context in which it occurs. Finally, the solution refers to the answer to the problem that helps to solve it.
The design patterns are descriptions of communicating objects and classes that are customized to solve a general design problem in a particular context. ― Gamma Erich, Helm Richard, Johnson Ralph, Vlissides John. Design Patterns: Elements of Reusable Object-Oriented Software
In this article, I would like to discuss about the Template Method, a Behavioral Pattern.
Behavior patterns focus on algorithms and assignment of responsibilities between objects. They describe not only patterns of objects or classes, but also patterns of communication between objects.
A template method defines the steps of an algorithm and allows the redefinition of one or more of these steps by subclasses. In this way, the template method protects the algorithm, the order of execution and provides abstract methods that can be implemented by concrete types.
- Define an algorithm framework in the form of a method, allowing some steps to be implemented by specific concrete classes.
- Sub-classes can redefine certain steps of an algorithm without changing its general structure.
- The Template Method can be used to implement parts of an algorithm once and leave it up to the concrete classes to implement the behavior according to their needs.
- It can be used when code reusability is desired without losing control of the algorithm.
- It presents an abstract class with primitive operations that subclasses define to implement steps of an algorithm.
- The abstract class implements a template method defining the skeleton of the algorithm
- The concrete classes implement the primitive operations to be executed in the template method.
It's worth enforcing that `templateMethod()` should be final, and therefore should not be overridden.
- Template Method uses inheritance to vary parts of an algorithm. It may become a problem in the future.
- It can be an important ally in the development of applications, as it provides a way to separate the variable behavior from the invariable behavior of an application.
- It also contributes to the implementation of the dependency inversion principle.
Practical Example in Swift
When creating the UI of a project programatically, i.e. setting up the interface without storyboards or XIBs, we need to perform a few basic steps, such as:
- Add the sub view to the view.
- Setup the constraints.
- Setup additional configuration.
So far, pretty simple. But these steps need to be implemented in the correct order. In case you try to run a piece of code that sets constraints to a view that has not been added yet, the application crashes, because there’s no view to apply those constraints to.
This seems like a good use case for Template Method. So, let’s see how it goes.
In Swift, we can create an abstract type to hold a blueprint of methods, and make our classes conform to it. This way we favor composition over inheritance, minimising one of the downsides of this pattern. So, we do that by declaring a Protocol.
Our protocol holds the three basic steps to configure views programmatically, and a fourth method
setupView() that’s going to be out template.
So we have the basic structure, but we don’t have our algorithm yet. In order to implement it, we are going to use Protocol Extensions.
Protocols can be extended to provide method, initializer, subscript, and computed property implementations to conforming types. This allows you to define behavior on protocols themselves, rather than in each type’s individual conformance or in a global function. - Apple documentation.
This is how our extension will look like:
Now we created our algorithm, in the classes that implement this protocol,
setupView() is the only method that needs to be called. The other ones will hold the implementation of the algorithm steps, for example:
The class conforms to the protocol, and configures the steps for the algorithm. And the only method called is our template method.
So, as we could see, the Template Method allows us to approach a common task that needs to be done routinely, and create an abstraction that reinforces the steps to be executed, as well as the order of execution. Besides that, it becomes a standard in the codebase, facilitating the communication with the team and with new developers.
Design Patterns - Elements of Reusable Object-Oriented Software was written by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides (also known as the Gang of Four, or GoF)
iOS Course: View code module (in Portuguese) - Article