Design Patterns – What Makes the Iterator a Design Pattern?

design-patternsiteratorobject-oriented-design

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

Best Answer

Most of the patterns from the GoF book have the following things in common:

  • they solve basic design problems, using object-oriented means
  • people often face these kind problems in arbitrary programs, indepently from the domain or business
  • they are recipes for making the code more reusable, often by making it more SOLID
  • they present canonic solutions to these problems

The problems solved by these patterns are so basic that many developers understand them mainly as workarounds for missing programming language features, which is IMHO a valid point of view (note that the GoF book is from 1995, where Java and C++ did not offer so many features as today).

The iterator pattern fits well into this description: it solves a basic problem which occurs very often, independently from any specific domain, and as you wrote by yourself it is a good example for "separation of concerns". As you surely know, direct iterator support is something you find in a lot of contempary programming languages today.

Now compare this to the problems you picked:

  • writing to a file - that is IMHO simply not "basic" enough. It is a very specific problem. Nor is there a good, canonic solution - there are lots of different approaches how to write to a file, and no clear "best practice".
  • Painter, Encoder: whatever you have in mind with that, those problems look even less basic to me, and not even domain independent.
  • having the "power" function available for different kind of objects: at a first glance, that could be worth beeing a pattern, but your proposed solution does not convince me - it looks more like an attempt to shoehorn the power function into something similar to the iterator pattern. I implemented a lot of code with engineering calculations, but I cannot remember a situation where an approach similar to your power function object would have helped me (however, iterators is something I have to deal with on a daily basis).

Moreover, I do not see anything in your power function example which could not be interpreted as an application of the strategy pattern or the command pattern, which means those basic parts are already in the GoF book. A better solution might contain either operator overloading or extension methods, but those are things are subject to language features, and that is exactly what the "OO means" used by the "Gang" could not provide.