Card 01/ 09
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.
Without the patternthe caller does index arithmetic
i = 0
while i < len(playlist.songs):
play(playlist.songs[i])
i += 1The loop reads songs, and depends on it being a list.
With the patternthe caller asks for the next item
songs = iter(playlist)
while True:
try:
play(next(songs))
except StopIteration:
breakThis 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.
| Pattern | What it does |
|---|---|
| Chain of Responsibility | Passes a request along a chain of handlers until one handles it. |
| Command | Turns a request into an object that can be stored, queued or undone. |
| Interpreter | Represents 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. |
| Mediator | Routes the communication between objects through one central object. |
| Memento | Captures an object's state so it can be restored later. |
| Observer | Notifies many objects when one object changes. |
| State | Changes an object's behaviour when its internal state changes. |
| Strategy | Swaps one algorithm for another behind a common interface. |
| Template Method | Fixes an algorithm's steps in a base class and lets subclasses fill some in. |
| Visitor | Adds operations to a class hierarchy without changing its classes. |
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