Refactoring with the Builder pattern
05 Jun 2018There have been some posts shared recently in the community about common software patterns and how they might help you writing code that is better structured and easier to read and maintain. One such pattern is the Builder Pattern. Simply put, applying this pattern allows for easier creation of complex objects, by hiding those complex details from the calling site.
The not so nice approach
In one area of our app we had the following code, responsible for creating two rather similar instances of UIButton
:
In here, we are executing a few different instructions, needed to setup the button according to the specific needs:
- create an instance with type
custom
- setting an image for the
normal
state - defining how the button content is displayed, with
contentMode
- adding an action for when the user taps the button
These are just some of the properties that you can set to configure a button, many others could be needed. And in this case, we are dealing with a standard UIKit
element, probably one of the first controls that you play with when you start developing for iOS, so most of these properties should be known by heart even for the most inexperienced programmer.
A better approach
That doesn’t mean we shouldn’t spend some time trying to come up with a way to make it easier to use, or make it more reusable. Because it is (always) a good practice to design your APIs having in mind that someone else might need to read / consume them even if you are the only developer in the project, we are going to extract the responsibility of creating a custom tailored instance of the button into a specific method, using the Builder pattern.
So, we can create an extension of UIButton
and add a couple of static methods:
We only left as parameters what depend on the context where the methods are called, in this case how the button behaves when tapped. This already looks better, we have specific methods that are clear on their intent, making easier to create instances of the desired type of buttons whenever they are needed that will always look the same.
Ah, I like this!
But we can do better, we can use the power of enums
to explicitly declare the different type of buttons:
And then, we can extend the declaration of the enum, by adding the builder method:
So now, if we want to create a camera button, we just need to:
Builders everywhere
This is a great pattern and we find ourselves using frequently, where another good use case is to configure a view controller after creating it from the storyboard as there are no methods to inject its dependencies:
This way it is clear what is needed to properly setup the view controller, making our code less error prone and more reliable.
(tested in Xcode 9.3 and Swift 4.1)
Thanks for reading!