Design Patterns in Swift: Part II— Behavioral Design Pattern

Lubaba Hasnain
8 min readJan 1, 2019

--

In the first article of the series, I discussed about Creational Design Patterns.
Now I will describe another set of patterns called Behavioral Design Patterns.

Behavioral Design Pattern deals with how objects interact. It describes how objects communicates with each other and how the steps of a task is broken among different objects so as to provide more flexibility and make the code more testable.

Let us jump to these 10 behavioral design patterns:

1. Chain of Responsibility

Chain of Responsibility is a behavioral design pattern that let us pass the requests among a chain of handlers where each handler decides either to process the request or to pass it along the chain.

There is an enum called Level to breakdown the Sports management into three levels: state, national & international. First let us create a class called Sports which will just hold the current sports management level.

Then we have the protocol called GameManagement which can pass the responsibility along the handler chain. The classes StateSportsTeam, NationalSportsTeam & InternationalSportsTeam implement this protocol. If the sports level does not belong to their management, they pass the responsibility to the higher management (or the handlers chain).

Running the code in the playground:

let stateSportsTeam = StateSportsTeam()
let nationalSportsTeam = NationalSportsTeam()
let internationalSportsTeam = InternationalSportsTeam()
stateSportsTeam.nextLevelManagement = nationalSportsTeam
nationalSportsTeam.nextLevelManagement = internationalSportsTeam
let sports1 = Sports(level: Level.international)
stateSportsTeam.manage(sports: sports1)
let sports2 = Sports(level: Level.national)
stateSportsTeam.manage(sports: sports2)
let sports3 = Sports(level: Level.state)stateSportsTeam.manage(sports: sports3)Output:
Managed by International Sports Management
Managed by National Sports Management
Managed by State Sports Management

2. Command Pattern

In Command pattern, the class that executes the command(called Invoker) is decoupled from the class which produces the command(ConcreteCommand) and from the class that knows how to perform it (Receiver).

Let us follow the below example.
The Invoker is the heart of the pattern. It can call the execute() method to perform an action without being aware of the concrete class ConcreteCommand and what it does. It only knows about the abstract type Command protocol.

ConcreteCommand class conforms to Command protocol and takes and instance of Receiver object in the initializer. It then calls the receiver object to perform certain task/operation.

Receiver is the class that does the actual work. It can be any business logic, database request or network operation.
Client is the class that creates the ConcreteCommand object and pass it into the invoker. It can be your view controller class.

Trying out the code:

let client = Client()
client.showPattern()
Output:
red

3. Iterator Pattern

This pattern is used for iterating over a collection of elements. It does not expose the data structure used in implementing it (array, dictionary or linked list) rather it gives an interface which iterates over the collection of elements without exposing its underlying representation.

Ever wondered how for-in loop works in Swift?
Swift has a built-in Sequence protocol which helps in creating iterators. The Sequence protocol gives sequential access to its elements by creating an iterator. IteratorProtocol is a type that supplies the values of a sequence one at a time.

The class MyBestFilms implements the Sequence protocol that creates a custom iterator. Every time the next() function is called, it returns the next element and store the current index.
This is absolutely great! You can create your own custom sequence.

Illustrating the point:

let myFilms = MyBestFilms(films: ["Godfather Trilogy", "Silence of the Lambs", "Call Me By Your Name"])for film in myFilms {
print(film)
}
Output:
Godfather Trilogy
Silence of the Lambs
Call Me By Your Name

4. Mediator Pattern

Let us take a scenario when two or more classes has to interact with each other. Instead of directly communicating with each other and getting the knowledge of their implementation, they can talk via a Mediator.

So, for example, there are two teams competing with each other to get selected in the finals of a game. Team A is The Avengers and Team B is The League of Extraordinary Gentlemen.
So instead of directly communicating with each other, they register to the mediator object and then they can send messages to each other via Mediator.

Two protocols are defined:
Protocol Receiver implemented by the Teams which has the abstract receive method that takes a message as a parameter.

Protocol Sender implemented by the Mediator which has the abstract method send that takes message and a Receiver type object as a parameter.
Our mediator iterates through each team in its list of teams. If the team A is sending the request, team B receives it and vice-versa.

Notice that the teams are not aware of each other. There is no reference of team A in team B and team B in team A.

Note: NSNotificationCenter uses Mediator Pattern

Let us try it out.

let mediator = Mediator()
let teamA = TeamA(name: "The Avengers")
let teamB = TeamB(name: "The League of Extraordinary Gentlemen")
mediator.register(candidate: teamA)
mediator.register(candidate: teamB)
mediator.send(message: "Selected for final! from \(teamA.name)", sender: teamA)
mediator.send(message: "Not selected for final! from \(teamB.name)", sender: teamB)
Output:
The League of Extraordinary Gentlemen received: Selected for final! from The Avengers
The Avengers received: Not selected for final! from The League of Extraordinary Gentlemen

5. Memento Pattern

Memento Pattern captures the current state of an object and store it in such a way that you can retrieve it at a later time when you would like to return to the previous state.

We’ve a protocol Memento with default implementation of save and retrieve methods.
save saves the `state` property with key in UserDefaults.
retrieve restores the `state` property using key from UserDefaults.
state is of type dictionary which stores the value with a unique key
key is used to retrieve the corresponding value from the state

Class Profile will implement Memento protocol. By implementing this protocol, we can save the entire class to persistent storage and then retrieve the state at later time.

Trying on playground:

var profile = Profile(name: "Nick Jonas", age: 36, key: "NickProfile")
profile.saveDetails()
profile = Profile(name: "Priyanka Chopra", age: 26, key: "PriyankaProfile")
profile.saveDetails()
let profile1Details = Profile(key: "PriyankaProfile")
let profileState = profile1Details.retrieveDetails()
print(profileState)
Output:
["age": 26, "name": Priyanka Chopra]

6. Observer Pattern

In this pattern, one object notifies other objects about its state change i.e. when the state of one object changes, other object which are subscribed to it gets notified about the state change.

So, it is a one-to-many relationship. The object whose state changes are called observable or subject and the objects which subscribe for changes on the observable are called observers.

The Observable protocol has three abstract methods:
add: for adding observers
remove: for removing observers
notify: for notifying all observers about its state change

Assume a scenario where an Apple Seller has to notify her customers about new apples arriving in her shop. As soon as new apples arrive, she notifies the customer who are added in the loop about the new apples. She can also remove the customers from the loop.

AppleSeller is the class that implements the Observable protocol. When the appleCount variable value changes, it calls the notify() method to notify the customers who are added to it.
Customer is a class that listens to the changes in the appleCount variable. As soon as this variable’s value changes, the customer gets updated via the update() method.

Here’s the usage:

let appleSeller = AppleSeller()let james = Customer(name: "James", observable: appleSeller, customerId: 101)
let david = Customer(name: "David", observable: appleSeller, customerId: 102)
appleSeller.appleCount = 10
appleSeller.remove(customer: james)
appleSeller.appleCount = 20
Output:
Hurry James! 10 apples arrived at shop.
Hurry David! 10 apples arrived at shop.
Hurry David! 20 apples arrived at shop.

7. State Pattern

State design pattern is a design pattern where an object needs to change his behavior when its internal state has changed. It appears as if the object changed its class.

First we define a protocol called Human which has a getter for getting the current state and a setter for setting the current state of the object.
The state will be carried by a class called Man.
The protocol ManState has three states: stand(), walk() and run(). It is implemented by three concrete classes: StandingState, WalkingState and RunningState.

To illustrate the point of this pattern:

let man = Man()let walkingState = WalkingState(man)
walkingState.walk()
print(man.getState().toString())
let runningState = RunningState(man)
runningState.run()
print(man.getState().toString())
Output:
The man is in walking position
Walking State
The man is in running position
Running State

You can see from the results that calling the same method on the same instance of a class is producing different results.

8. Strategy Pattern

This pattern defines a family of algorithms, each one of them written in a separate class allowing us to select which algorithm to execute at runtime.

We define a protocol called Strategy and it has a method named convert to convert the number into a format decided by the user at runtime.
We implement two algorithms: BinaryStrategy to convert number to binary and HexStrategy to convert number to hex.

The class Convert has a property called Strategy so any of the classes can be used which implement the Strategy protocol.
At runtime we pass the the class instance of type Strategy depending upon we choose the algorithm that does binary number conversion or we choose the algorithm that does hex number conversion.

Running the above code:

let binaryConvert = Convert(number: 2, strategy: BinaryStrategy())
binaryConvert.update()
let hexConvert = Convert(number: 123, strategy: HexStrategy())
hexConvert.update()
Output:
Binary is 10
Hex is 7b

9. Template Pattern

In this pattern, the base class defines the template of an algorithm and let the subclass implement these abstract methods in the same way they are defined in the base class without changing the overall structure.

In Template method pattern, classes interact using only base classes that implements the algorithm steps. In swift, we’ll use interface delegation for that.
Suppose, in an office there is an office schedule for all the employees.
Protocol Office has an abstract method called officeSchedule(). Class XYZOffice will implement this protocol.

All the employees have shared responsibilities like work and get payment for their work.
Protocol Employee has two abstract methods: work() and getPaid().
Different employees will do different kind of work but still they follow the same template of working and getting paid.

Illustrating the point:

let xyzOfficeDev = XYZOffice(employee: Developer())
let xyzOfficeManager = XYZOffice(employee: ProductManager())
xyzOfficeDev.officeSchedule()
xyzOfficeManager.officeSchedule()
Output:
Developer has worked 40 hours/week this month
Developer has earned Rs 50,000 this month
Product Manager has worked 55 hours/week this month
Product Manager has earned Rs 80,000 this month

10. Visitor Pattern

Visitor design pattern separates the algorithms from the objects on which they operate i.e. the operational logic is moved from each elements of a group into a new class. The new class will perform the operational logic using the data from those elements.

Each element accepts a visitor which does the logic in another class. So the structure of the visited class is not changed at all.
Each country should be able to accept a visitor. So we declare a protocol named Country which has a method to accept a visitor.
The visitor is named CountryVisitor.
Let us define concrete classes for our Country.

And now let’s implement the CountryVisitor protocol and showcase this design pattern.

Running in the playground

let countries: [Country] = [India(), Brazil(), China()]
let names = countries.map { (country: Country) -> String in
let
visitor = CountryVisitorName()
country.accept(visitor: visitor)
return visitor.visitorName
}
print(names)
Output:
["Chen", "Ramesh", "Antonio"]

Here is the link to the playground files.

All Behavioral Design Patterns in Swift are fully covered in this article with working examples.

Behavioral Design pattern focuses on communication and interaction of objects, powerful dynamic interfaces and object composition which should be used for designing softwares.

--

--