For the last three weeks we’ve been looking at creational factory patterns: Factory Method, Simple Factory and Abstract Factory patterns. This week we’ll cover a commonly used behavioural pattern, the Iterator pattern.
The Iterator Pattern
The Gang of Four book defines the Iterator pattern as follows:
“Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.”
This formalises the way we sequentially access the elements of a collection, without needing to know anything about the internal implementation of the collection. Using an iterator hides those internals from the client application, so that we as developers can easily change the internal code without affecting any class that uses it.
The iterator pattern has become so commonplace in modern programming languages that it has become more of a programming idiom rather than a design pattern.
While on that topic, let’s take a brief detour to look at programming idioms because the topic comes up quite often in discussions about design patterns.
Programming Idioms vs Design Patterns
Programming idioms are low-level design patterns specific to a programming language. An idiom describes how to solve implementation-specific problems using the features of that language, such as memory management in C++. Idioms use particular language features or work around a specific language deficiencies.
This is in contrast to design patterns which address general design principles. Design patterns are not specific to any language. Ideally design patterns should be language independent.
There isn’t an absolute dividing line between programming idioms and design patterns. Idioms represent low-level solutions specific to a programming language. Design patterns represent high-level language-agnostic solutions to common programming problems. Idioms often directly address the concrete implementation of a design pattern.
Another difference between an idiom and a pattern is that of size. An idiom is generally small, like “use an interface type for a collection variable”, while patterns tend to represent larger solutions.
Iterator Pattern in the Java Collection API
The usual way that the iterator pattern is implemented is by defining a separate iterator object that has the responsibility of accessing and traversing the collection object. A method is then defined in the collection to return an iterator object.
In Java, all of the collection classes in the java.util
package implement the Iterator
pattern to step through the collection. The top-level Collection
interface defines an iterator()
method that returns an Iterator
object.
The important methods of the Java Iterator
interface are shown below:
public interface Iterator{ public boolean hasNext(); public E next(); public default void remove(); }
The hasMore()
method returns a boolean
result to indicate that the collection has more elements. The next()
method returns a reference to the next element in the collection. The remove()
method removes the last element returned by the iterator (this is optionally supported). Each concrete collection implements these methods in its own way (i.e. polymorphically).
Most other modern programming languages also have collection and record set classes that implement the Iterator pattern.
Iterator Pattern: Example Code
Back in our first person shooter game, we’ve equipped all our soldiers with weapons (see the previous post on the Template Method design pattern). During the game, we can find new weapons, and possibly even lose a weapon or have it taken away from us during a fight.
We’d occasionally like to take stock and see what weapons we have. We’d like to choose the best weapon for the occasion. Stakes and decapitation work on a Vampire
. We need to shoot a Werewolf
with a silver bullet. And anything that can destroy the brains of a Zombie
will do the trick.
How do we check all our weapons? With an iterator, of course!
import java.util.*; public abstract class BaseSoldier { // Weapon collection - an ArrayList is used here for illustration. // We'd create an appropriate concrete collection in the constructor. private Collectionweapons = new ArrayList<>(); private Weapon currentWeapon; // checking weapons public void checkWeapons() { // using the iterator Iterator it = weapons.iterator(); while (it.hasNext()) { Weapon weapon = it.next(); // check if a weapon is appropriate for the task // at hand, then set it to the current weapon. ... currentWeapon = weapon; } } // more BaseSoldier code } // end of class
The checkWeapons()
method doesn’t know or care how the weapons are stored. It uses the iterator to sequentially access the weapons one at a time. The weapons
collection could refer to any concrete class implementing the Collection
interface, and the iterator would work identically.
Fail-fast and Fail-safe Iterators in Java
If necessary, we could expose the collection of weapons to client code for external iteration, though we’d have to take care to avoid concurrent modification of the collection by both the BaseSoldier
code and the client code. Different concrete collection classes have different behaviours which have to be handled appropriately.
Iterators over ArrayList
and HashMap
views are fail-fast. If the collection is modified at any time after the iterator is created, other than with the iterator’s remove()
method, the iterator will throw a ConcurrentModificationException
. This means that the iterator fails quickly and cleanly if the collection is concurrently modified.
On the other hand, fail-safe iterators don’t throw exceptions if a collection is modified while iterating over it. They operate on clones of the collection, not on the original collection. Iterators over CopyOnWriteArrayList
and ConcurrentHashMap
views are fail-safe.
Conclusion
The iterator pattern is a very easy pattern to understand and implement. This is why it is often thought of as a programming idiom.
In the weeks ahead, we’ll continue examining some of the more useful design patterns. Stay tuned! And don’t forget to share your comments and questions.