I have been wondering what it is that makes the Iterator special when compared to other similar constructs, and that made the Gang of Four list it as a design pattern.
The Iterator is based on polymorphism (a hierarchy of collections with a common interface) and separation of concerns (iterating over the collections should be independent from the way the data is structured).
But what if we replace the hierarchy of collections with, for example, a hierarchy of mathematical objects (integer, float, complex, matrix etc.) and the iterator by a class representing some related operations on these objects, for example power functions. The class diagram would be the same.
We could probably find many more similar examples like Writer, Painter, Encoder, and probably better ones, that work the same way. However I have never heard any of these being called a Design Pattern.
So what makes the Iterator special?
Is it the fact that it is more complicated because it requires mutable state for storing the current position within the collection? But then, mutable state is usually not being considered desirable.
To clarify my point, let me give a more detailed example.
Here's our design problem:
Let's say we have a hierarchy of classes and an operation defined on the objects of these classes. The interface of this operation is the same for each class, but the implementations can be completely different. It is also assumed that it makes sense to apply the operation multiple times on the same object, say with different parameters.
Here's a sensible solution for our design problem (practically a generalization of the iterator pattern):
For separation of concerns, the implementations of the operation should not be added as functions to the original class hierarchy (operand objects). Since we want to apply the operation multiple times on the same operand, it should be represented by an object holding a reference to the operand, not just by a function. Therefore the operand object should provide a function that returns the object representing the operation. This object provides a function that performs the actual operation.
An example:
There's a base class or interface MathObject
(stupid name, I know, maybe someone has a better idea.) with derived classes MyInteger
and MyMatrix
. For each MathObject
an operation Power
should be defined that allows calculation of square, cube and so on. So we could write (in Java):
MathObject i = new MyInteger(5);
Power powerOfFive = i.getPower();
MyInteger square = powerOfFive.calculate(2); // should return 25
MyInteger cube = powerOfFive.calculate(3); // should return 125