Chapter 7. Behavioral Patterns – Iterator, Mediator, and Observer

This chapter presents you with three other behavioral patterns, which support communication between objects. Objects keep their independence and sometimes their anonymity. The iterator pattern is often used with array, collection, and dictionary objects. The mediator allows communication between two objects without knowing each other's identities and the observer patterns mirror the publish/subscribe methodologies that are well known in distributed systems.

This chapter is divided in three sections:

  • The iterator pattern
  • The mediator pattern
  • The observer pattern

The iterator pattern

This pattern is commonly used in many languages with an array or a collection of objects. It allows iteration over a list of objects contained in a collection.

Roles

The iterator pattern allows you to iterate sequentially over an aggregated object of objects without having to know how the collection is structured.

Design

Here, you'll find the generic UML class diagram of the pattern, but note that we will not implement it using this way.

Indeed, Swift provides some types that will simplify the implementation of the iterator pattern, without having to produce all of the needed requirements by hand.

Why reinvent the wheel? The following figure represents the generic UML class diagram:

Design

Participants

As with every pattern described up to now, I will tell you what the participants in this pattern are even if we will not see all of them in our implementation of the pattern:

  • Collection: This is an abstract class that implements the association of the collection with items and the CreateIterator() method
  • ConcreteCollection: This is concrete collection subclass that link the CurrentItem object to a ConcreteItem object and the Iterator interface to the ConcreteIterator object
  • Iterator: This is the abstract class, which implements the association of the iterator and the collection items and methods
  • ConcreteIterator: This is a concrete subclass that links our currentItem to the ConcreteItem object
  • Item: This is the abstract class of the collection items
  • ConcreteItem: This is a concrete Item subclass used by ConcreteIterator and ConcreteCollection

Collaboration

The iterator keeps in memory the current item in the collection. It can also calculate and predict the next object of the iteration.

Illustration

You are developing a game in which you can have up to say, four players. You want to be able to iterate over all the four players to do something. In our sample, we will display the name of each player.

Implementation

The implementation provided here comes from ideas discovered on the Lilly Labs website at http://lillylabs.no/2014/09/30/make-iterable-swift-collection-type-sequencetype/.

Well, given our illustration what we want to be able to do is to iterate using a for…in loop construct.

All thanks to Swift, we have some elements that will simplify the implementation of this pattern.

Indeed, Swift proposes a SequenceType protocol and an AnyGeneratorType<T> class, which implements the GeneratorType protocol.

The SequenceType protocol defines a protocol that allows us to iterate over elements of a collection using the for…in loop construct. It requires that the class implements the generate() method, which returns an object conforming to the GeneratorType protocol.

AnyGenerator<T> is a class that conforms to the GeneratorType protocol, where <T> means Item of any type.

Having said this, how do we use all of the preceding functions to easily iterate over a collection of any type? Let's say, we have the following class:

class Player {
  var name: String!
  
  init(name: String) {
   self.name = name
  }
}

Therefore, we define a simple Player class where we pass a string in the constructor, which corresponds to the name of the player.

We suppose that we have four players in our game and want to be able to iterate over each of them to display their name.

Therefore, the final code to test will be something like the following:

for player in players {
  print("analysing (player.name)")
}

Now, how to complete our code with a bonus, something that will works with any class that we want to iterate over? Well, we will use another concept provided by Swift: extension.

The first thing to be done is to create an object or struct that we will let us iterate over any class type:

struct OurCollection<T> {
  let items: [T]
} 

Therefore, we define a struct that we call OurCollection, where items are of type T.

Now, we will be able to write the following:

let player1 = Player(name: "Helmi")
let player2 = Player(name: "Raphael")
let player3 = Player(name: "Adrien")
let player4 = Player(name: "Alain")


let players = OurCollection(items:[player1,player2, player3, player4])

However, the for…in loop will still not work, as shown in the following screenshot:

Implementation

Even though, the players don't implement the SequenceType protocol. Here is the magic:

extension OurCollection: SequenceType {
  typealias Generator = AnyGenerator<T>
  
  func generate() -> Generator {
    var i = 0
    return anyGenerator {
      return i >= self.items.count ? nil : self.items[i++]
    }
  }
}

Wow! Lot of new things here:

First, we create an extension of the OurCollection struct by telling that we want to implement the SequenceType protocol.

So we implement the generate() method, which will return the next type T object in the iteration. Also, note the line:

  func generate() -> Generator {

Generator is an alias of AnyGenerator<T>:

  typealias Generator = AnyGenerator<T>

We use this to simplify the writing. We can remove the type alias statement and write:

func generate() -> AnyGenerator<T> {

Another function is the anyGenerator function tha you see here:

    return anyGenerator {
      return i >= self.items.count ? nil : self.items[i++]
    }

The Swift 2.0 documentation says that the anyGenerator function has the following signature:

func anyGenerator<Element>(body: () -> Element?) -> AnyGenerator<Element>

The purpose of this function is to return a GeneratorType instance whose next method invokes body and returns the result.

So here, we start from index 0 to index self.items.count value and add the sel.items[i++] in the new GeneratorType instance. The new GeneratorType instance is returned when i is superior to a number of elements in the items array.

We can also write the function such as:

  func generate() -> Generator {
    var i = 0
   let seq = anyGenerator {i < self.items.count ? self.items[i++] : nil}
    return seq
 }

And also like this:

  func generate() -> Generator {
    var i = 0
   return anyGenerator {i < self.items.count ? self.items[i++] : nil}
 }

Here, we use a closure with the anyGenerator function to return a new sequence of elements that we can iterate over. Our final code is as follows:

import Foundation

struct OurCollection<T> {
  let items: [T]
}

class Player {
  var name: String!
  
  init(name: String) {
   self.name = name
  }
}


extension OurCollection: SequenceType {
  typealias Generator = AnyGenerator<T>
  
  func generate() -> Generator{
    var i = 0
    // Construct a AnyGenerator<T> instance, passing a closure
    // that returns the next type T object in the iteration
    return anyGenerator {
      return i >= self.items.count ? nil : self.items[i++]
    }
  }
}


let player1 = Player(name: "Helmi")
let player2 = Player(name: "Raphael")
let player3 = Player(name: "Adrien")
let player4 = Player(name: "Alain")


let players = OurCollection(items:[player1,player2, player3, player4])

for player in players {
  print("Name: (player.name)")
}

Open the iteratorPattern project, build and run it. You will now see the following result:

Implementation
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset