Iterator Pattern

Question: Can we encapsulate the iteration ?

In design pattern, an important concept it encapsulate what varies. The iteration caused by different collections of objects being returned from the menu is changing? Can we encapsulate this? Let’s work through the idea…

  1. To iterate through the breakfastItems we use the size() and get() methods on the ArrayList:
for (int i = 0; i < breakfastItems.size(); i++) {
    MenuItem menuItem = (MenuItem) breakfastItems.get(i);
}
  1. And to iterate through the lunch items we use Array length field and the array subscript notation on the MenuItem Array.
for (int i = 0; i < lunchItems.length; i++) {
    MenuItem menuItem = lunchItems[i];
}
  1. Now what if we create an object, let’s call it an Iterator, that encapsulates the way we iterate through a collection of objects ? Let’s try this on the ArrayList.
Iterator iterator = breakfastMenu.createIterator();
while (iterator.hasNext()) {
    MenuItem menuItem = (MenuItem) iterator.next();
}
  1. Let’s try that on the Array too:
Iterator iterator = lunchMenu.createIterator();
while (iterator.hasNext()) {
    MenuItem menuItem = (MenuItem) iterator.next();
}

The idea above is a Design Pattern called the Iterator Pattern. Next, let’s see its formal definition.

Definition

The definition of iterator pattern in wekipedia is:

In object-oriented programming, the iterator pattern is a design pattern in which an iterator is used to traverse a containter and access the container's elements. The iterator pattern decouples algorithms from containers; in some cases, algorithms are necessarily container-specific and thus cannot be decoupled.

For simplicity, iterator pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

Benefits

What benefits it brings ?

  • It allows us to iterate different absurb data structure uniformly, making the iteration trivial. That is the traversal operation is defined for an aggregate object without chaning its interface.
  • It enables the traversal of data structure without exposing representation of that data structure. That is encapsulation benefit.
  • Since it is a kind of lazy implementation, i.e. we ask one and it gives us one at a time, therefore our collection can be infinite, e.g. Fibonacci array.
  • It keeps track of where we are in the iteration, so we can pause and then start.

Structure

It relies on an interface called Iterator. Once we have this interface, we can implemnet Iterators for any kind of collection of objects: arrays, lists, hashtables,…

The UML diagram is shown as follows.

Notice: Concrete iterable products particular concrete iterator, not iterator, and pass itself. So that concrete iterator has a reference to concrete iterable.

Implementation:


// iterable interface
Interface Inventory {
    InventoryIterator getIterator()}

// an concrete iterable
Class HandHoldInventory implements Inventory {

    public Item Right { getter; private setter }
    public Item Left { getter; private setter }

    public HandHoldItemInventory (Item right, Item left) {
        this.Right = right; this.Left = left;
    }

    public InventoryIterator getIterator() {
        Return new HandHoldInventoryItorator(this);
    }

}

// Iterator interface
Interface InventoryIterator {
    boolean isDone()    //hasNext()
    void next()
    Item current()
}

Interface Item {}

// a concrete iterator
Class HandHeldInventoryIterator implements InventoryIterator {

    HandHeldInventory inventory;
    Int index = 0;

    public HandHeldInventoryIterator (HandHeldInventory i) {
        this.inventory = I;
    }

    public boolean isDone() {
        Return this.index < 2;
    }

    public void next() {
        this.index == 1;
    }

    public Item current() {
        Switch (this.index) {
            Case 0 : return this.inventory.Right;
            Case 1 : return this.inventory.Left;
            Others : return null;
        }
    }
}

{% endcodeblock %}

Next, we can traverse the `HandHeldInventory` as follows,
{% codeblock lang:java %}

Inventory inv = new HandHeldInventory();

InentoryIterator iter = inv.getIterator();

while(iter.isDone()) {
    Iter.current();
    // do something cool
    Iter.next();
}

Iterator in Java

source

An iterator over a collection. Iterator takes the place of Enumeration in the Java Collections Framework. Iterators differ from enumerations in two ways:

  • Iterators allow the caller to remove elements from the underlying collection during the iteration with well-defined semantics.
  • Method names have been improved.

Important methods

  • boolean hasNext(): returns true if the iteration has more elements.
  • E next(): returns the next element in the iteration. It may throw NoSuchElementException (RuntimeException) if the iteration has no more element.
  • default void remove(): removes from the underlying collection the last element returned by this iteration. Note that:
    • This method is an optional operation.
    • This method can be called only once per call to next().
    • It may throw UnsupportedOperationException, if the remove operation is not supported by this iterator.
    • It may also throw IllegalStateException(RuntimeException), if the the next method has not yet been called, or the remove method has already been called after the last call to the next method.

   Reprint policy


《Iterator Pattern》 by Tong Shi is licensed under a Creative Commons Attribution 4.0 International License
  TOC