Book Image

Swift 2 Design Patterns

By : Julien Lange
Book Image

Swift 2 Design Patterns

By: Julien Lange

Overview of this book

Table of Contents (15 chapters)
Swift 2 Design Patterns
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

The builder pattern


Unlike the abstract factory pattern, which will produce parts of products of the same family, the builder pattern will help us build the finalized product that consists of several parts.

Roles

The main purpose of the builder pattern is to abstract the building of complex objects from its actual construction. Having the same construction process can create different representations of the product.

This pattern can be used when:

  • A client needs to construct complex objects without having to know its implementation

  • A client needs to construct complex objects that need to have several implementations or representations

Design

The following figure shows the generic UML class diagram of the builder pattern:

Participants

This pattern is quite simple as it has only a few participants:

  • Director: This class constructs the product using the interface of the AbstractBuilder class.

  • AbstractBuilder: This class defines the method signature that allows the construction of all the parts of the product, and it contains a signature of a method that returns the product once this is built.

  • ConcreteBuilder: This is the Concrete class that implements the method of the AbstractBuilder class.

  • Product: This is the finalized product. The product contains all the parts of the watch.

Collaborations

The client creates the ConcreteBuilder and Director classes. The Director class will then build an object if the client asks him to do so by invoking the constructor and returns the finalized product to the client.

Illustration

Using the AbstractFactory method, we can use the builder pattern to build a watch. As we've seen that a watch has several parts: a dial and band. A watch can have two sizes too, and as we have already seen, the representation of the dial or band depends on the size of the watch too.

Implementation

If we want to build some watches that are represented with a dial and band, we will define a Director class that will define the construction order of all the parts of our watches and return the finalized watch to the client.

The Director class will call all the constructors who are in charge to construct one part of the watch. To implement this, we will reuse the existing code of the abstract factory pattern and add the following code.

Open the Builder.playground file in Xcode to see the added code at the bottom of the file:

//Our builder1
class BuilderGoldMilanese38mmWatch: AbstractWatchBuilder {
  override func buildDial() {
    watch.band = MilaneseBand(size: BandSize.SM)
  }
  override func buildBand() {
    watch.dial = GoldDial(size: WatchSize._38mm)
  }
}

//Our builder2
class BuilderAluminiumSportand42mmWatch:AbstractWatchBuilder {
  override func buildDial() {
    watch.band = SportBand(size: BandSize.ML)
  }
  override func buildBand() {
    watch.dial = AluminiumDial(size: WatchSize._42mm)
  }
}

//our Director class
class Director {
  var builder: AbstractWatchBuilder?
  init(){
    
  }
  
  func buildWatch(builder: AbstractWatchBuilder){
    builder.buildBand()
    builder.buildDial()
  }
}

Usage

To simulate our client, we will tell our director to create two watches:

  • A 42 mm aluminium dial with a sports band

  • A 38 mm gold dial with a milanese band

The code for the example is as follows:

//We will build 2 Watches :
//First is the Aluminium Dial of 42mm with Sport Band
let director = Director()
var b1 = BuilderAluminiumSportand42mmWatch()
director.buildWatch(b1)

// our watch 1
var w1 = b1.getResult()
w1.band?.color
w1.band?.type.rawValue
w1.band?.size.rawValue
w1.dial?.size.rawValue
w1.dial?.material.rawValue

//Our 2nd watch is a Gold 38mm Dial with Milanese Band
var b2 = BuilderGoldMilanese38mmWatch ()
director.buildWatch(b2)

// Our watch 1
var w2 = b2.getResult()
w2.band?.color
w2.band?.type.rawValue
w2.band?.size.rawValue
w2.dial?.size.rawValue
w2.dial?.material.rawValue

The result is shown in Playground like this:

Note

Swift allows the use of closure that simplifies the creation of our complex objects. Regarding the example that we provided earlier, we can write the following code to build our two watches.

Implementation using closures

Here, we don't need to use the Director and ConcreteBuilder classes. Instead, we will tell our Watch class that the builder will be in the closure.

In the previous example, remove the Director, AbstractBuilder, and ConcreteBuilder classes.

We just need to write the Watch class, as shown in the following code (you can find the following code in the BuilderClosures.playground file accompanying this chapter):

//our Product Class : a Watch
//The builder will be in the closure
class Watch{
  var dial:IWatchDial?
  var band:IWatchBand?
  typealias buildWatchClosure = (Watch) -> Void
  
  init(build:buildWatchClosure){
    build(self)
  }
}

Then, to simulate our client, we can write the following code which will call the appropriate constructor assigned to the band or dial property of the Watch object:

//Simulate our clients

let Gold42mmMilaneseWatch = Watch(build: {
  $0.band = MilaneseBand(size: BandSize.ML)
  $0.dial = GoldDial(size: WatchSize._42mm)
})

The result is as follows: