Model building

In Swift, we have the nice benefit of having structs automatically generate their constructor. This saves a lot of boilerplate code when creating new instances of structs.

Let's consider this Article struct. You could use this to represent an article for a blog, for example:

struct Article {
let id: String
let title: String
let contents: String
let author: String
let date: Date
var views: Int
}

Creating new Article instances is quite labor-intensive, as you need to gather all the parameters and use them at once in the same code place. However, using the builder pattern, you could pass the builder around your code and, when the whole content is ready, create the article structure.

In editors such as IntelliJ for Java, you could automatically generate the builder for this struct. In Swift, Xcode doesn't provide such capacities, but a tool such as Sourcery or SourceKit could help you generate the builder:

  1. We can place the builder in an extension, so as not to pollute the original struct with the builder code, as follows:
extension Article {
  1. Create a nested Builder class. We do not use a struct here, so we can do the chaining:
class Builder {
  1. Next we can declare all the temporary properties, all optional, and with default values for some that we may want default values for, as follows:
private var id: String = randomIdGenerator()
private var title: String?
private var contents: String?
private var author: String?
private var date: Date = Date()
private var views: Int = 0
  1. After this, we can declare all the setter methods. Note that each setter will let you chain the calls for easily setting multiple values:
func set(id: String) -> Builder {
self.id = id
return self
}

func set(title: String) -> Builder {
self.title = title
return self
}

func set(contents: String) -> Builder {
self.contents = contents
return self
}

func set(author: String) -> Builder {
self.author = author
return self
}

func set(date: Date) -> Builder {
self.date = date
return self
}

func set(views: Int) -> Builder {
self.views = views
return self
}
  1. Finally, we create the most important method, the build() method, which returns the new instance of the original type:
func build() -> Article {
return Article(
id: id,
title: title!,
contents: contents!,
author: author!,
date: date,
views: views)
}
}
}

Now, you can use this builder across all your applications.

Imagine you have a series of forms that will let you fill in an article, one step after another. For example, you can imagine this form builder is available as a command line tool, each prompt executing after each other, gathering data from the user input:

let builder = Article.Builder()

builder.set(author: prompt("What's your name?"))
// ask the user for the title
builder.set(title: prompt("What's the title for your article"))

// later in the code, get the message
builder.set(contents: prompt("What do you want to say?"))

let article = builder.build()
show(article)

While the builder pattern is very powerful for passing data around, it is very cumbersome to write the code manually. However, great tools such as Sourcery can help us generate the code.