Iterator Design Pattern

1.  Classification
2.  Intent
3.  Motivation
4.  Structure
5.  Consequences
6.  Sample Code
Classification   top
Iterator is a behavioral pattern. Also known as Cursor. Behavioural patterns are concerned with algorithms and the assignment of responsibilities between objects, they describe patterns of objects or classes and the patterns of communication between them." [Gamma, p.221]
 
Intent  top
The intent of this design pattern is to provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation. In other words, an iterator allows a client to access a contents of a certain data structure  without knowing about the internal representation of the contents.
 
Motivation   top
A data structure such as list should give the user a way to access its elements in such a way that it does not expose its internal structure. Also, you should be able to manipulate that list in different ways, depending on what you want to accomplish, but at the same time you do not want to all your manipulation procedures into the list interface even if you can predict which ones you might need. The Iterator Pattern allows you to do those things. The idea of this pattern is to take the responsibility for access and manipulation of the data structure out of the list object and put it into the iterator object. The iterator class will define the interface for accessing the data structure's elements. This way we can define different iterators for different ways of manipulating a data structure.
 
Structure   top
Iterator Structure
 Participants

  1. Iterator - defines an interface for accessing the elements and traversing the elements
  2. ConcreteIterator - implements the Iterator interface and keeps track of the current position in                                    the traversal of the aggregate
  3. Aggregate - defines an interface for creating an Iterator object
  4. ConcreteAggregate - implements the Iterator creation interface to return an instance of the                                             proper ConcreteIterator
Consequences   top
There are three major consequences. [Gamma, p. 260]
  1. Iterator Pattern supports variations in the traversal of an aggregate. Every time you want to change the traversal algorithm, you just replace the iterator instance with a different one.
  2. Iterators simplify the Aggregate interface.
  3. More than one traversal can be pending on an aggregate. An iterator keeps track of its own traversal state. Therefore you can have more than one traversal in progress at once.
 
Sample Code   top
This sample code will show how Iterator Pattern works. It is written in Java. In this example, we will print out an array of numbers in two ways: 1) in the order the numbers are in the array, 2) backwards. Here we have an abstract aggregate class that creates an abstract iterator class. Abstract iterator class defines the procedures for data structures, such as "first", "next", "isDone", and "CurrentItem". We, also, have two concrete aggregate classes that create two concrete iterator classes. Those concrete iterator classes have their own implementations of the procedures specified in the abstract iterator.

aggregate.java

 import java.util.Vector;

public abstract class aggregate {

public abstract iterator createiterator();

public void append(Object anObj){
elements.addElement(anObj);
}

public void remove(Object anObj){
elements.removeElement(anObj);
}

public Object currentItem(int n){
return elements.elementAt(n);
}

public int count(){
return elements.size();
}

private Vector elements = new Vector(5);
}

iterator.java
public interface iterator {

void first();
void next();
boolean isDone();
Object currentItem();


concreteaggregatea.java
public class concreteaggregatea extends aggregate{

public concreteaggregatea(){
}

public iterator createiterator(){
return new concreteiteratora(this);
}



concreteiteratora.java
public class concreteiteratora implements iterator{

public concreteiteratora(aggregate anObj){
obj = anObj;
}

public void first(){
state = 0;
}

public void next(){
if (!isDone()){
state++;
}
}

public boolean isDone(){
if (state>obj.count()-1){
return true;
}
return false;
}

public Object currentItem(){
return obj.currentItem(state);
}

private int state;
private aggregate obj;
}


concreteaggregateb.java
   public class concreteaggregateb extends aggregate{

public concreteaggregateb(){
}

public iterator createiterator(){
return new concreteiteratorb(this);
}
}
 

concreteiteratorb.java

public class concreteiteratorb implements iterator{

public concreteiteratorb(aggregate anObj){
obj = anObj;
}

public void first(){
state = obj.count()-1;
}

public void next(){
if (!isDone()){
state--;
}
}

public boolean isDone(){
if (state<0){
return true;
}
return false;
}

public Object currentItem(){
return obj.currentItem(state);
}

private int state;
private aggregate obj;
}

 

iteratorexample.java

public class iteratorexample {
public static void main(String[] args) {

aggregate testA = new concreteaggregatea();
testA.append(new Integer(1));
testA.append(new Integer(2));
testA.append(new Integer(3));
testA.append(new Integer(4));
testA.append(new Integer(5));

aggregate testB = new concreteaggregateb();
testB.append(new Integer(1));
testB.append(new Integer(2));
testB.append(new Integer(3));
testB.append(new Integer(4));
testB.append(new Integer(5));

System.out.println("Print Test A:");
iterator iterA = testA.createiterator();


iterA.first();
while (!iterA.isDone()){
Integer n = (Integer)iterA.currentItem();
iterA.next();
System.out.println("Value: " + n);
}


System.out.println("Print Test B:");
iterator iterB = testB.createiterator();


iterB.first();
while (!iterB.isDone()){
Integer n = (Integer)iterB.currentItem();
iterB.next();
System.out.println("Value: " + n);
}
}
}