The Iterator Pattern provides a way to
access the elements of an aggreagate object sequentially
without exposing its underlying respresentation.
An Iterator allows access to an aggregate’s (a collection) elements without exposing its internal structure.
Iterating over an aggreagate using an iterator encapsulates this task in another object other than the aggregate itself.
Thereby we relieve the aggregate of the responsibility of supporting operations for traversing its data.
The iterator provides a common interface for traversing the items of an aggregate, allowing you to use polymporphism when writing code that makes use of the items of the aggregate. In other words, when we write methods that take iterators as parameters, we are using polymorphic iteration. That means we are creating code that can iterate over any collection as long as it supports the Iterator interface. The implementation of the underlying collection doesn’t matter, we can still write code to iterate over it.
The Iterator Pattern is commonly used with the Composite Pattern to iterate over its components.
We distinguish between “internal” and “external” iterators.
Using an external iterator, the client controls the iteration by calling next() to get the next element. An internal iterator is controlled by the iterator iself. This way, the iterator is stepping through the elements and thereby controls
the iteration itself. To get apply operations on the elements we have to pass the internal iterator a method. With internal iterators the client doesn’t have control of the iteration, which might not be required if a single operation should be applied to all elements.
The following example shows two restraunt menus, where both implement the same aggregate interface Menu. Each menu has menu items stored in different types of collections. With the Iterator Pattern it is possible to iterate over these items without
knowing the underlying type of the aggregate.
Each aggregate implements the createIterator() method which is declared in the Menu interface:
Each menu will have a menu item that implements the following interface:
Next we define the two menu classes (aggregates). PancakeHouseMenu uses an ArrayList<MenuItem> for its items.
The member menuItems is an ArrayList which implements the Iterator interface and therefore provides the iterator method that returns an iterator to the elements of the ArrayList.
The next concrete aggregate that implements the Menu interface is the DinerMenu class. Because it uses a standard array we will need a DinerMenuIterator defined afterwards:
Also DinerMenu returns its concrete implementation of the Iterator<MenuItem> interface, DinerMenuIterator:
The client in this example is the Waitress which stores the menus in an ArrayList<Menu> and uses iterator from java.util. Using the printMenu() method we iterate over the menus aggregate and call printMenu(Iterator<?>) on the items:
To test this program we use the following snippet: