Card 01/ 09

ConceptDifficulty: Intermediate3 min

Iterator Pattern: Walking a Collection Without Knowing How It Is Stored

A list, a tree and a database cursor can all be read one item at a time by the same loop.

The Iterator pattern gives a collection a separate object that returns its elements one at a time, so that code reading the collection never needs to know how it is stored. This card covers the problem that calls for it, the intent, and when it fits.

The problem is a caller tied to a collection's internals. A loop over a list counts an index from zero to the length. The same loop cannot read a tree, which has no index, or a result set that arrives from a server in pages. Each new kind of storage needs a new loop, and when a collection changes how it stores its elements, every loop over it breaks.

A loop that knows the storage, and a loop that asks for the next item

Without the patternthe caller does index arithmetic

py
i = 0
while i < len(playlist.songs):
    play(playlist.songs[i])
    i += 1

The loop reads songs, and depends on it being a list.

With the patternthe caller asks for the next item

py
songs = iter(playlist)
while True:
    try:
        play(next(songs))
    except StopIteration:
        break

This is what for song in playlist: does for you.

The Gang of Four state the intent as: provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation. An aggregate is any object that holds a collection of elements.

A television's channel-up button is a familiar picture. You see the next channel without knowing how the set stores its list of channels. The picture breaks at the end: the channels wrap round to the first, while an iterator stops and says it has no more.

Iterator is one of eleven behavioural patterns, the family concerned with which object does which part of the work, and how objects communicate.

The behavioural family, with this pattern marked
PatternWhat it does
Chain of ResponsibilityPasses a request along a chain of handlers until one handles it.
CommandTurns a request into an object that can be stored, queued or undone.
InterpreterRepresents a small language's grammar as classes and evaluates its sentences.
Iterator (this topic)Visits the elements of a collection without exposing how it is stored.
MediatorRoutes the communication between objects through one central object.
MementoCaptures an object's state so it can be restored later.
ObserverNotifies many objects when one object changes.
StateChanges an object's behaviour when its internal state changes.
StrategySwaps one algorithm for another behind a common interface.
Template MethodFixes an algorithm's steps in a base class and lets subclasses fill some in.
VisitorAdds operations to a class hierarchy without changing its classes.
Iterator

Use it when

  • A collection is stored in a way callers should not depend on, such as a tree, a linked structure, or pages from a server.
  • Several walks over the same collection must be able to run at once, each at its own position.
  • The elements are produced on demand, and holding all of them in memory at once would be wasteful.

Avoid it when

  • The collection is a plain list or array, whose language already provides an iterator.
  • Callers need random access by position, which an iterator does not give.
  • The collection changes while it is being walked, unless the iterator's behaviour in that case is defined.

← → move through sections and cards