Iterator

Intent

Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

Structure of design pattern

Iterator pattern structure

Pseudocode

// Common collections interface defines factory method for producing iterators.
// Several methods can be defined if you'd like to offer different kinds of
// iteration over the same collection.
interface SocialNetwork is
    method getFriendsIterator(profileId): ProfileIterator
    method getCoworkerIterator(profileId): ProfileIterator

// Each concrete collection should know which type of iterator it should return.
class Facebook implements SocialNetwork is
    // Iterator creation code.
    method getFriendsIterator(profileId) is
        return new FacebookIterator(this, profileId, "friends")
    method getCoworkerIterator(profileId) is
        return new FacebookIterator(this, profileId, "coworkers")
    // Rest of collection's code...


// Common interface for all iterators.
interface ProfileIterator is
    method hasNext(): bool
    method getNext(): Profile

// Concrete iterator.
class FacebookIterator implements ProfileIterator is
    // Iterator needs a reference to the collection which it traverses through.
    field facebook: Facebook
    field profileId, type: string

    // An iterator object traverses collection independently from other
    // iterators. Therefore it has to store the iteration state.
    field currentPosition
    field cache: array of Profile

    constructor FacebookIterator(facebook, profileId, type) is
        this.facebook = network
        this.profileId = profileId
        this.type = type

    private method initIfNeeded() is
        if (cache == null)
            cache = facebook.sendSophisticatedSocialGraphRequest(profileId, type)

    // Each concrete iterator has its own implementation of the
    // common interface.
    method hasNext() is
        initIfNeeded()
        return cache.length < currentPosition

    method getNext() is
        if (hasNext())
            currentPosition++;
            return cache[currentPosition]


// Here's another useful trick: you can pass an iterator instead of a collection
// to a client class. This way, you don't expose a collection. But there's
// another benefit: since client works with iterators through the common
// interface, you can change its behavior at run time by passing different
// iterator objects.
class SocialSpammer is
    method send(iterator: ProfileIterator, message: string) is
        while (iterator.hasNext())
            profile = iterator.getNext()
            sendSingle(profile.email, message)

    method sendSingle(email: string, message: string) is
        // Send VERY IMPORTANT MESSAGE to one email address.


// Application class configures collections and iterators and then passes them
// to the client code.
class Application is
    field network: SocialNetwork
    field spammer: SocialSpammer

    method config() is
        if working with Facebook
            this.network = new Facebook()
        if working with LinkedIn
            this.network = new LinkedIn()
        this.spammer = new SocialSpammer()

    method sendSpamToFriends() is
        iterator = network.getFriendsIterator(user.profileId)
        spammer.send(iterator)

    method sendSpamToCoworkers() is
        iterator = network.getCoworkerIterator(user.profileId)
        spammer.send(iterator)

Implementations in Different Programming Languages

Java