Introduction

Iterator pattern is used to access the elements of a collection object in sequential manner without any need to know its underlying representation. Iterator pattern falls under behavioural pattern category. An aggregate object such as a list should give you a way to access its elements without exposing its internal structure. Moreover, you might want to traverse the list in different ways, depending on what you need to accomplish. The Iterator pattern providing a uniform interface for traversing many types of aggregate objects. The key idea is to take the responsibility for access and traversal out of the aggregate object and put it into an Iterator object that defines a standard traversal protocol.

Intent

  • Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
  • Abstraction provided by the iterator pattern allows you to modify the collection implementation without making any changes outside of collection.
  • It enables to create a general purpose API component that can be used to iterate through any collection of the application.

Implementation

Client uses Aggregate interface directly, but access to the collection’s elements is encapsulated behind the additional level of abstraction called Iterator. Each Aggregate derived class knows which Iterator derived class to create and return. After that, the Client relies on the interface defined in the Iterator base class. Iterator defines interface which is implemented by ConcreateIterator to iterate over object defined by Aggregate.

Example

To understand we will consider below example. Iterator implement a custom iterator which will traverse based on the Container.

// NameRepo create concrete class implementing the Container interface. 
// This class has inner class NameIterator implementing the Iterator interface.
public interface Iterator {
   public boolean hasNext();
   public Object next();
}

public interface Container {
   public Iterator getIterator();
}

public class NameRepo implements Container {
   public String names[] = {"RB" , "JH" ,"JU" , "LO"};

   @Override
   public Iterator getIterator() {
      return new NameIterator();
   }

   private class NameIterator implements Iterator {

      int index;

      @Override
      public boolean hasNext() {
      
         if (index < names.length){
            return true;
         }
         return false;
      }

      @Override
      public Object next() {
      
         if(this.hasNext()){
            return names[index++];
         }
         return null;
      }		
   }
}

public class IteratorPattern {
  
   public static void main(String[] args) {
      NameRepo names = new NameRepo();

      for(Iterator iter = names.getIterator(); iter.hasNext();){
         String name = (String)iter.next();
      } 	
   }
}

Advantage

  • Iterator design pattern hides the actual implementation of traversal through the collection and client programs just use iterator methods.
  • The iterator pattern can be implemented in a customised way.
  • We can use several iterators on the same collection.