GoF Definition: Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
Iterators are generally used to traverse a container to access its elements.
Suppose there are two companies: Company A and Company B. Company A stores its employee records (name, etc.) in a linked list and Company B stores its employee data in a big array. One day the two companies decide to work together. The iterator pattern is handy in such a situation. We need not write codes from scratch. We’ll have a common interface through which we can access data for both companies. We’ll simply call the same methods without rewriting the codes.
Similarly, say, in a college, the arts department may use array data structure and the science department may use linked list data structure to store their students’ records. The main administrative department will access those data through the common methods—it doesn’t care which data structure is used by individual departments.
It has many parts. I have created the related folders for these. So, first see the structure. Here science subjects are stored in a linked list and arts subjects are stored in an array. We are printing the papers using the iterators. IIterator is the common interface here. Its methods are specifically implemented in ScienceIterator (contained in science class) and ArtsIterator (contained in arts class). We are printing the papers through the common methods IsDone() and Next() here. (You can use the other two methods also, namely, First() and currentItem()—those are also implemented.)
For simplicity, you can omit either Science(and ScienceIterator) or Arts(and ArtsIterator). But we kept both to show you the power of this pattern.
High-level structure of the parts of the program is as follows:
//ISubject.java
package aggregate;
import iterator.*;
public interface ISubject
{
public IIterator CreateIterator();
}
//IIterator.java
package iterator;
public interface IIterator
{
void First();//Reset to first element
String Next();//get next element
Boolean IsDone();//End of collection check
String CurrentItem();//Retrieve Current Item
}
//Arts.java
package aggregate;
import iterator.*;
public class Arts implements ISubject
{
private String[] subjects;
public Arts()
{
subjects = new String[2];
subjects[0] = "Bengali";
subjects[1] = "English" ;
}
public IIterator CreateIterator()
{
return new ArtsIterator(subjects);
}
//Containing the ArtsIterator
public class ArtsIterator implements IIterator
{
private String[] subjects;
private int position;
public ArtsIterator(String[] subjects)
{
this.subjects = subjects;
position = 0;
}
public void First()
{
position = 0;
}
public String Next()
{
return subjects[position++];
}
public Boolean IsDone()
{
return position >= subjects.length;
}
public String CurrentItem()
{
return subjects[position];
}
}
}
// Science.java
package aggregate;
//for Linked List data structure used here
import java.util.LinkedList;
import iterator.*;
public class Science implements ISubject
{
private LinkedList<String> subjects;
public Science()
{
subjects = new LinkedList<String>();
subjects.addLast("Maths");
subjects.addLast("Comp. Sc.");
subjects.addLast("Physics");
}
@Override
public IIterator CreateIterator()
{
return new ScienceIterator(subjects);
}
//Containing the ScienceIterator
public class ScienceIterator implements IIterator
{
private LinkedList<String> subjects;
private int position;
public ScienceIterator(LinkedList<String> subjects)
{
this.subjects = subjects;
position = 0;
}
public void First()
{
position = 0;
}
public String Next()
{
return subjects.get(position++);
}
public Boolean IsDone()
{
return position >= subjects.size();
}
public String CurrentItem()
{
return subjects.get(position);
}
}
}
//IteratorPatternEx.java
package iteratorpattern.demo;
import iterator.*;
import aggregate.*;
class IteratorPatternEx
{
public static void main(String[] args)
{
System.out.println("***Iterator Pattern Demo*** ");
ISubject Sc_subject = new Science();
ISubject Ar_subjects = new Arts();
IIterator Sc_iterator = Sc_subject.CreateIterator();
IIterator Ar_iterator = Ar_subjects.CreateIterator();
System.out.println(" Science subjects :");
Print(Sc_iterator);
System.out.println(" Arts subjects :");
Print(Ar_iterator);
}
public static void Print(IIterator iterator)
{
while (!iterator.IsDone())
{
System.out.println(iterator.Next());
}
}
}
If you have gone through the above code, probably you now have a fair idea of the power of an iterator and the significance of this pattern. We can support different variations for the traversal of an aggregate (the interface to create an Iterator object), and above all, it simplifies the interface.
But we must be careful while traversing and any kind of modification during that traversal period can cause damage to us. We can take a backup first to deal with this type of scenario, but it is obvious that taking the backup and reexamining it at some later stage is also a costly operation.