Real World: iOS Design Patterns
Design Pattern
is a common topic in talks, forums and even in a 15 min break conversation at work. You can find a lot of stuff on books or the internet about it and a lot of examples using rubber ducks 🦆, coffee shop ☕ and pizza stores 🍕.
When I started studying I usually understand the pattern but I had a lot of trouble, thinking about how to apply them to my code. I understand that the Factory
pattern is used to create objects but why do I need it? Do I really need a Factory
to create my objects?
My goal with this post is to bring some real examples of some design patterns that I used in my projects.
Strategy
The strategy pattern enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives runtime instructions as to which in a family of algorithms to use.
We can use different algorithms runtime based, in other words, we don't care how the implementation is done.
An algorithm needs an object that knows how to fly
, a Duck class
knows how to fly
and a Rocket class
too. Our algorithm doesn't care if our implementation needs to spread its wings or a gallon of gas.
Problem solved using strategy
It this project we needed to be able to receive a viewController
but we also need it to have some predefined behaviors and that's a perfect place to apply the Strategy
pattern. A common ViewController
in mobile applications is a Login
so just create a protocol that defines our LoginViewController
actions and dependencies.
I mean that our LoginViewController
can be injected in our project, we don't care about the UI if it has a tableView
, any animation
, or validation methods but we need it to know how to perform a login
. You can read more about this particular problem here.
Factory
The factory method pattern deal with the problem of creating objects without having to specify the exact class of the object that will be created.
The factory pattern is useful when you need to create objects at runtime. So if the user wants a cheese pizza you create a CheesePizza()
if he/she wants a pepperoni so PepperoniPizza()
ftw.
Problem solved using factory
In the same project that we use the strategy
pattern to solve our viewController
injection problem, we use a factory
pattern to be able to create objects at runtime passing to them all the dependencies they need.
We needed to push an instance of LoginViewController
which can be created using different approaches like Storyboards
, xib
or view coded
. We had a factory instance, which can be injected changing the way the object that will be created by the factory changing the factory itself.
With an instance of a Factory
we just need to call the build
method. This factory can be an instance of ViewCodedLoginViewControllerFactory
or StoryboardLoginViewControllerFactory
we don't really care, we just need it to implement the build
method that returns a LoginViewController
.
Here we have one factory for each kinds of objects, but we can have one factory that knows how to build a ViewController
from storyboard
, xibs
or viewcoded
.
Decorator
The decorator pattern allows the behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class.
This is my favorite pattern, the classic example of decorator pattern is the Coffee shop that wants to add whip cream to its coffee and calculate the new price and description based on the beverage.
Problem solved using decorator
We need different API versions for each service call, this can be done in many different ways but we use this pattern to add a custom Header
to a Request
. With this approach, we can also be ready if, in the future, one API call should add another parameter to its header.
We also needed to filter results in a request. Which can be done creating a new method, or changing how your request work. We decided to use a Decorator
to add this behavior because our service was used in others classes and we want to change the least possible numbers of lines in our previous implementation.
Adapter
The adapter pattern is a software design pattern that allows the interface of an existing class to be used as another interface. It is often used to make existing classes work with others without modifying their source code.
Think an adapter as a real adapter. You need your Nintendo 64 🎮 that has a composite video as its video output to work with your new 4k TV 📺. So you need a Composite-HDMI adapter.
Problem solved using adapter
We needed to last four digits of a Card
model and also be compatible with PKPaymentPass
. In other words, created an adapter to turn one PKPaymentPass
instance into Card
.
But we can also mix patterns creating more reusable and maintainable code, for example, mixing our adapter with the strategy
pattern. We don't really need a Card
object we just need the lastNumbers
so why we don't create a protocol to do that and be compatible with PKPaymentPass
, Card
and any other object that our project may need.
Finally
Design patterns
help me a lot to create more reusable code, save me some time when I needed to change some stuff on codes and because of them, some tasks are much easier then they should be.
If you don't get it how the patterns work here are some great posts about Strategy, Factory, Decorator, and Adapter.
Ps: If you like this post, share it on Twitter, recommend it on medium, or both =). This really helps me to reach more people. Thanks a lot.