Strategy pattern in Swift
Recently I gave a talk at NSCoder Night Madrid about the Strategy pattern. People loved it! I felt that our community will benefit from this knowledge too. So in this guide, I will explain Strategy pattern for iOS and provide some examples.
What is it?
Firstly we should define this pattern. In Wikipedia, it is defined as follow:
In computer programming, the strategy pattern is a behavioral software design pattern that enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use.
🤯 ⁉️ This definition is very theoretical, so I think we could define it easier:
Encapsulates algorithms in classes, making them reusable and interchangeable at runtime.
Classification
The design patterns are classified into 3 categories according to their objectives:
- Creational
- Structural
- Behavioural
Yes, Strategy pattern is a behavioural pattern because it’s related to the behavioural of the objects. Easy, right?
When we should use it
There are many cases when we can use it. Let’s talk about three very specific scenarios in which we can see a clear value of the Strategy pattern.
1️⃣ Different ways to do the same
When you need to do the same thing in your code by different ways, it’s a clear example that you could use it.
2️⃣ Instead of inheritance
If you need to extend the functionality of a class and for doing this, you need to create a new class who inherits from it.
3️⃣ Alternative to if/else blocks
This is my favourite. Sometimes, if you look at a class, you can see that it has too much if/else or switch blocks, I mean, conditional blocks. This is a sign that this class has more responsibilities than it should. Using a Strategy pattern would help you distribute them.
Real Example
Imagine we need to create a Logger class, who prints a message in the console. Also, this class allows you to print stylized messages: lowercase, uppercase and capitalized. So, a possible implementation could be something like this:
Then, we would have an enum to specify which styles are available and a function log with a switch block inside to print the message in the console in the different styles.
Not bad, but really printing the message using different styles is the responsibility of the logger? What happens if we have twenty styles instead of only three? We should modify this class by adding the new styles inside the enum and the log function as well. 😅
According to the scenarios that we saw previously, this could be a good example where Strategy pattern could help us.
To explain how to do it, we will answer three questions and use a diagram, which I extracted from the book Design Patterns by Tutorials, available in Ray Wenderlich’s store, where we can differentiate all the participants very well.
- What: A protocol that defines the action that we want to encapsulate. In our example, the action would be log a message.
- Who: An object who contains an object who conforms the strategy. In our example, it could be an object who using the strategy log the message.
- How: Specific implementations of the strategy. Each implementation is different. In our example, we would have three strategies, one for each style.
So, the previous example using strategy would look like this:
And here how we can use it:
More examples
Let’s see more real examples where we can use the Strategy pattern.
📅 Calendar selection
In my company, eDreams ODIGEO, an online travel agency, users can choose between one-way trips or round trips. So, when we need to open the calendar to select the dates, depending on the type of trip that has been selected, the strategy of selection is different. For example, if it’s a round trip, the return date must be later than the departure date.
So, we have two selection strategies and when we open the calendar we specify which strategy should be used:
👮🏻 Form validation
When we use forms in our applications, we have many types of fields, texts, numbers, passwords, emails … In addition, each one has its own validation conditions. Then, we could define a strategy to validate, and each field would know how to validate itself.
🎨 Draw UITableView cells
To draw cells would also be useful. Imagine that we need to draw very different cells. Then, we would have a drawer that, using a view model, would draw the specific cell.
💵 Payment in a shopping cart
Methods of payment, exactly, when in our apps we provide several payment methods to pay the shopping cart: cash, cards, checks … In this case, we would use a specific strategy for each method, so when we start the action of payment only we will need to specify the amount and the payment interface.
🔫 Exchange weapons in a game
Changing the context, in the games the player exchanges weapons or shots using them. The action is the same for all weapons, but each weapon has its own way of firing, and the player does not need to know, it is what each weapon knows what to do when the player shots.
Why we should use it
The strategy is one of the most useful and simple design patterns. Also, if we use this pattern, you are doing a lot of things well and maybe you did not know:
Meet some SOLID principles
- Single responsibility. When we create strategies to do different things, we get that our original class has fewer responsibilities.
- Open / Close. If we use strategies to extend the functionality of the objects we don’t need to update the original object. As in our first example, if would add a new style, we only need to create a new strategy. Otherwise we would need to add a new case in our Styles enum.
Best practices
Use design patterns is a good practice when we are talking about software design.
Code testability
If we reduce the responsibilities of our objects, directly, we will do our objects more testables.
I hope this article helps you to learn a little more the Strategy pattern, that as I said before it has many pros and its implementation is not complex.
Be careful: when we find a new design pattern, we want to use it everywhere. But wait! We must analyze whether we should use it or not. Sometimes we do over-engineering.
Thanks for reading my tutorial. Share it if it was useful for you or if you think could be useful for someone. Feel free to comment below if you have any doubts or any suggestion of improvement.