When we adhere strictly to the SOLID principle in coding and develop any functionality, you may notice that the initialization method of your class has more parameters than the usual coding practice. From the perspective of an end user, this can complicate the process of creating an object of our class. Certain standard implementations are required during the object creation which the end user should not necessarily have to provide, but due to decoupling and composition, they become necessary.
So, how do we address this issue?
Let’s consider an example where we want to obtain a car object that is either an SUV or a sport car. During the car creation process, there are certain predefined elements that should not be requested from the end user. These aspects should be managed internally, but how?
Our primary objective is to ensure that our feature is decoupled and follows proper coding principles while being easily adaptable by the end user, who should not have to understand the internal class details but simply request an SUV or sport car.
This is where the builder pattern comes into play.
Essentially, the builder pattern is a creation pattern used for generating objects of a particular feature. It acts as a mediator between the end user and our feature, handling the creation process based on the end user’s requirements. The end user only needs to request a SUV or a sport car, and the builder will create the object accordingly and deliver it to the end user.
Initially, we create a Director that provides the car object as per the specified requirement.

class CarDirector {
func makeSUVCar() -> Car
func makeSportCar() -> Car
}

This is a public class that serves as a single point of contact for the end user to create a car object.
However, if we only offer these two methods to the end user, they may not be able to customize the car object according to their needs. To address this, we request a Builder from the end user as shown below:

class CarDirector {
private let builder: Builder
init(builder: Builder) {
self.builder = builder
}
func makeSUVCar() -> Car {
// Implementation will be added later
}
func makeSportCar() → Car {
// Implementation will be added later
}
}

Our director is prepared, and now we must create a builder. It is important to note that the builder should be a protocol or interface, not a class or struct, as this would violate the SOLID principle.

Protocol Builder {
func setSeats(_ number: Int)
func setEngine(_ engine: Engine)
func setGPS()
func getCar() -> Car
}

The Builder protocol has been established, and now we can implement it in the SUVBuilder and SportCarBuilder classes.

class SuvBuilder: Builder {
private var car = CarImp()
func setSeats(_ number: Int) {
car.setSeats(number)
}
func setEngine(_ engine: Engine) {
car.setEngine(engine)
}
func setGPS() {
car.setGPS()
}
func getCar() -> Car {
car
}
}class SportCarBuilder: Builder {
private var car = CarImp()
func setSeats(_ number: Int) {
car.setSeats(number)
}
func setEngine(_ engine: Engine) {
car.setEngine(engine)
}
func setGPS() {
car.setGPS()
}
func getCar() -> Car {
car
}
}

Now we need to create a car and an engine, and then we will be finished.

Protocol Car {
func setSeats(_ seats: Int)
func setEngine(_ engine: Engine)
func setGPS()
func description() -> String
}class CarImp: Car {
private var seats: Int?
private var engine: Engine?
private var isGPSEnabled: Bool = falsefunc setSeats(_ seats: Int) {
self.seats = seats
}
func setEngine(_ engine: Engine) {
self.engine = engine
}
func setGPS() {
self.isGPSEnabled = true
}
func description() -> String {
var description = “Car”
if let seats = seats {
description += “ with (seats) seats”
}
if let engine = engine {
description += “ with (engine.ccValue()) cc engine”
}
if isGPSEnabled {
description += “ with GPS”
}
return description
}
}class EngineImp: Engine {
private let cc: Int

required init(cc: Int) {
self.cc = cc
}

func ccValue() -> Int {
cc
}
}

Now, we have completed all the necessary preparations. It is time to update our Director code as shown below:

class CarDirector {
private let builder: Builder

init(builder: Builder) {
self.builder = builder
}

func makeSuv() -> Car {
builder.setSeats(4)
builder.setEngine(EngineImp(cc: 2000))
return builder.getCar()
}

func makeSportCar() -> Car {
builder.setSeats(2)
builder.setEngine(EngineImp(cc: 5000))
builder.setGPS()
return builder.getCar()
}
}

Alright, the “Make car” functionality is now ready. Let’s use it in the code. The end user simply needs to follow the steps below and they don’t have to worry about the specific properties of the SUV or Sport type car or how to create it. They can rely on a single source.

let suvBuilder = SuvBuilder()
let suvCarDirector = CarDirector(builder: suvBuilder)
let suvCar = suvCarDirector.makeSuv()
debugPrint(suvCar.description())let sportBuilder = SportCarBuilder()
let sportCarDirector = CarDirector(builder: sportBuilder)
let sportCar = sportCarDirector.makeSportCar()
debugPrint(sportCar.description())

As you can see, we only need to ask for the Builder of the respective class type and we don’t have to pass in detailed parameters of the car here. If you need a different configuration for the car, you just need to create a different builder instead of writing everything in a single place and making the initialization method heavy.

Thanks for reading! :)

Builder Pattern in swift was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.

​ Level Up Coding – Medium

about Infinite Loop Digital

We support businesses by identifying requirements and helping clients integrate AI seamlessly into their operations.

Gartner
Gartner Digital Workplace Summit Generative Al

GenAI sessions:

  • 4 Use Cases for Generative AI and ChatGPT in the Digital Workplace
  • How the Power of Generative AI Will Transform Knowledge Management
  • The Perils and Promises of Microsoft 365 Copilot
  • How to Be the Generative AI Champion Your CIO and Organization Need
  • How to Shift Organizational Culture Today to Embrace Generative AI Tomorrow
  • Mitigate the Risks of Generative AI by Enhancing Your Information Governance
  • Cultivate Essential Skills for Collaborating With Artificial Intelligence
  • Ask the Expert: Microsoft 365 Copilot
  • Generative AI Across Digital Workplace Markets
10 – 11 June 2024

London, U.K.