Builder Pattern in Swift for Beginners

activesludge
Dec 19, 2020 · 6 min read

“Have you ever not been able to create an object, just because you haven’t got all the parameters in hand?”

Image for post
Image for post
Gif by Jambonbon on Tumblr

I hope you are not hungry, because we will use hamburgers as metaphor.

Table of Contents

1. Introduction

Image for post
Image for post

In case of a hamburger, the initializer would look like this.

Image for post
Image for post

To create a Hamburger object, we have to fill each parameter requested by init.

Image for post
Image for post

What if we needed an hamburger without any sauce or any topping? Or what if I want to add toppings first then sauces? Or what if there is a case that we don’t have all the parameters at hand?

We can create alternative init functions. But it’s a duplication of code. Even if we tried, half way there, we would think “There has to be a better way”.

That is when the topic of this article, comes in handy. Builder design pattern is a creational design pattern that builds an object step by step without having to change the recipe, like a hamburger.

You can even turn builder function to composable to have more elegant looking dot syntax. A most of 3rd party swift libraries, makes developer’s life easier by taking advantage of builder pattern, such as RxSwift.

Image for post
Image for post
Builder with composables. Used as dot syntax. Looks way more professional.

Implementations may vary from developer to developer. You can make this more advanced or primitive, whichever is suited for your needs.

Below implementation is a basic version and using metaphor. Nevertheless, it will give you a good grasp on the concept.

We will use Playground. So create a new .playground, save it and proceed.

2. Director, Builder, Product

Image for post
Image for post

Director accepts inputs and coordinates with the builder. This is usually a view controller or a helper class that’s used by a view controller. It takes a builder as a parameter, and uses the returned Product however it wants.

Tip: Since the Builder is a dependency of the Director, what we will do below is making it “loosely coupled”. Which is a good practice for future. However, it doesn’t have to take a builder as a parameter. The builder can also be embedded inside the director. It is called “tightly coupled” and usually is a bad practice.

Builder is the one accepts step-by-step inputs and handles the creation of the product. This is often a class, so it can be reused by reference. Here is where we can implement our “setters”.

Tip: A way to make the builder more advanced, is to creating Builder as a protocol, and having different concrete Builder classes to implement necessary Builder protocol functions, such as “build()”. And implement each concrete class however you want.

Product is the complex object to be created. This can be either a struct or a class, depending on desired reference semantics. It’s usually a model, but it can be any type depending on your use case.

Tip: I couldn’t come up with a tip about Product, but here’s a one for hamburger! Minimize the amount of spice you mix to the meat. Rest the meat at least half an hour. Flat out the minced meat wider than the bread’s width.

3. When should you use it?

This pattern works especially well when a product requires multiple inputs. The builder abstracts how these inputs are used to create the product, and it accepts them in whatever order the director wants to provide them. Below are some real life examples:

  • User fills a form (sign up, survey, etc.)
  • User creates custom object (question, flash card, game level, collage, etc.)
  • User creates their order (pizza toppings)

4. Implementation

Create Product

We first define Hamburger, which has properties for meat, sauce and toppings. Why are they “let”, because once you make a hamburger, you can’t change it.

  1. We declare Meat as an enum. Let’s say each hamburger must have exactly one meat selection. (I’m not sure whether tofu can be classified as a meat selection. Sorry if that’s wrong.)
  2. We define Sauces and Toppings as an OptionSet. This will allow you to combine multiple sauces together. We’re gonna need more than pickles for a good burger!
  3. CustomStringConvertible extensions will help us print a readable string.

Tip: OptionSet is a protocol that presents a mathematical set interface to a bit set. It helps us implement single, multiple or no selection option way of structures. Don’t worry about it now. Yet definitely check it out later. For more info: https://developer.apple.com/documentation/swift/optionset

Create Builder

We declare properties for meat, sauces and toppings, which exactly match the inputs for Hamburger. Unlike a Hamburger, you declare these using var to be able to change them. You also specify private(set) for each to ensure only HamburgerBuilder can set them directly.

Since you declared each property using private(set), you need to provide public methods to change them. You do so via addSauces(_:), removeSauces(_:), addToppings(_:), removeToppings(_:) and setMeat(_:).

Lastly, you define build() to create the Hamburger from the selections. private(set) forces consumers to use the public setter methods. This allows the Builder to perform validation before setting the properties.
For example, you might want to ensure a meat is available prior to setting it.

Implement Director

A BurgerShop knows how to create two burgers: createCheeseBurger and createVegetarianBurger. Director can implement its own functions.

Moment of Truth

With Director, using predefined Builder functions:

Image for post
Image for post

Remember: In real life, the Director has usually a tableView or textView or anything. And it builds as inputs come from the user.

What if we don’t have a predefined function and will build our burger as inputs come?

Without predifened functions:

Image for post
Image for post

5. Be careful when

Instead, consider providing convenience initializers to create the product.

6. Conclusion

  • The director accepts inputs and coordinates with the builder; the product is the complex object that’s created; and the builder takes step-by-step inputs and creates the product.
  • This pattern can be more advanced or more primitive regarding with the requirement or architectural decisions. Directors can use multiple builders as parameter. Builders can create composable objects for passing it to the next operation.

I hope this article will be useful to you. Have a great one.

References
raywenderlich.com
refactoring.guru/design-patterns/builder
developer.apple.com/documentation/swift

Swift2Go

a place where Swift Developers share knowledge.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store