Iterator Pattern

The Iterator pattern allows you to navigate through a collection of data (aggregate) using a common interface without knowing about the underlying implementation. To accomplish this, the Iterator pattern suggests that a Container object should be designed to provide a public interface in the form of an Iterator object for different client objects to access its contents. Example iterators in Java are ResultSet, java.util.Iterator, Enumeration, etc. Iterators usually have methods such as hasMoreElements, isDone, getNextElement, remove, getFirst, currentItem, etc.

We usually have two types of iterator:

Internal Iterator:

  • The collection itself offers methods to allow a client to visit different objects within the collection. For example ResultSet contains the data and also offers methods such as next() to navigate through the item list. Usually the collection (Personnel for example) can extend or implements an iterator.
  • There can be only one iterator on a collection at any given time.
  • The collection has to maintain or save the state of iteration.
  • GoF says internal (passive) iterator itself is responsible for controlling the iteration.

External Iterator:

  • The iteration functionality is separated from the collection and kept inside a different object referred to as an iterator. In most cases the iterator can simply implement java.util.Iterator. Usually the collection itself returns an appropriate iterator. For example, the java.util.Vector.elements() returns an Enumeration or Collection interface returns an iterator through iterator() method.
  • There can be multiple iterators on a given collection at any given time.
  • There can be different types of iterators depending on the way they traverse the aggregate.
  • The iterator has to maintain or save the state of iteration not the collection itself.
iterator.jpeg
  • GoF has another definition of external and internal iterators and who controls the iterations: when iterator controls the iteration then the iterator is called internal (passive), where as when the client controls the iteration the iterator is called external (active).

Implementation

  • An iterator may be implemented to do more than simply returning the next object in line. For instance, an iterator object can return a selected set of objects (instead of all objects) in a sequential order. This filtering can be based on some form of input from the client. These types of iterators are referred to as filtered iterators.
  • cursor is a type of iterator in which the aggregate defines the traversal algorithm and iterator stores the state of iteration.
  • A robust iterator ensures that insertions and removals won't interfere with traversal, and it does it without copying the aggregate.
  • Null Iterator always returns true in isDone() method. It can be used in tree traversals where every node returns an iterator for traversing its sub-tree. Leaves can return a null iterator for uniformity.

Sample Code

Internal:

// acts as both container and iterator
public class AllCandidates implements Iterator {
 
    private Vector data;
    Candidate nextCandidate;
 
    @Override
    public boolean hasNext() {
    }
 
    @Override
    public Object next() {
    }
 
    @Override
    public void remove() {
    }
 
    public void setData(Vector d){
        this.data = d;
    }
}
public class Test{
    public test(){
        AllCandidates ac = new AllCandidates();
        while(ac.hasNext()){
            ac.next()
        }
    }
}

Now and external iterator:

//container
public class AllCandidates {
 
    private Vector data;
    private Iterator iterator;
 
    Iterator getEligibleCandidates(){
        return new EligibleCandidatesIterator(this);
    }
 
    Vector getAllCandidates(){
        return data;
    }
 
    public Vector getData() {
        return data;
    }
 
    public void setData(Vector data) {
        this.data = data;
    }
}
 
public class EligibleCandidatesIterator implements Iterator {
 
    private AllCandidates dataInside;
 
    public EligibleCandidatesIterator(AllCandidates input){
        this.dataInside = input;
    }
 
    @Override
    public boolean hasNext() {
    }
 
    @Override
    public Object next() {
    }
 
    @Override
    public void remove() {
    }
}
 
public class Client {
    public void test(){
        AllCandidates ac = new AllCandidates();
        ac.setData(...);
        Iterator itr = ac.getEligibleCandidates();
 
        while(itr.hasNext()){
            itr.next();
        }
    }
}

Related Patterns

  • Iterators are often applied to recursive structures such as Composites
  • Iterators can use factory methods to instantiate the appropriate Iterator subclass
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License