Iterator Design Pattern

Abdullah Al Noman
3 min readMar 19, 2021

Today I am going to discuss a very simple behavioral design pattern called the Iterator design pattern. Almost every programming language has data structure and collection, hence they provide iterator and we iterate over the objects. Sometimes we use for loop or forEach loop to do that but we need to make sure that our implementation should not be exposed. According to the book, the main intent is like

“Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation. ”

Ok, let's see some examples of iteration now.

// If a simple array is used to store gadgets
for (int i = 0; i < gadgetList.length; i++)
Gadget gadget= gadgetList[i]);
// If ArrayList is Java is used, then we would iterate
// over them as:
for (int i = 0; i < gadgetList.size(); i++)
Gadget gadget= (Gadget)gadgetList.get(i);

If we could have some other collection like a tree, set, Map, etc. Then our way of iteration should be changed, that’s why we are going to build a generic way of iterating over a collection of its independent type.

UML Diagram Iterator Pattern

In this pattern, we have a common interface Collection for the client as it decouples it from the implementation of your collection objects. The GadgetCollection implements that createIterator() method for returning the iterator for its collection. The responsibilities of ConcreteIterator named as GadgetIterator is to instantiate a ConcreteIterator that can iterate over its collection. Consider a situation where you are adding multiple gadgets in an application and you have to traverse and display all the gadgets. So, we are writing the following codes for that.

Coding Implementation:

// Our Model Class
public class Gadget {
private String name;

public Gadget(String name) {
this.name = name;
}

public String getName() {
return name;
}
}
// Our Collection Interface
public interface Collection {
public Iterator createIterator();
}
// Concrete Collection Class
public class GadgetCollection implements Collection{
static final int MAX_ITEMS = 6;
int numberOfItems = 0;
Gadget[] gadgetList;

public GadgetCollection() {
gadgetList = new Gadget[MAX_ITEMS];

addGadget("Phone");
addGadget("Tablet");
addGadget("Computer");

}

private void addGadget(String gadget) {
Gadget gadget1 = new Gadget(gadget);
if(numberOfItems >= MAX_ITEMS){
System.out.println("Full");
}else{
gadgetList[numberOfItems] = gadget1;
numberOfItems += 1;
}
}

@Override
public Iterator createIterator() {
return new GadgetIterator(gadgetList);
}
}
// Iterator Interfacepublic interface Iterator {
public boolean hasNext();
Object next();
}
// Concrete Iteratorpublic class GadgetIterator implements Iterator{
Gadget[] gadgetList;
int position = 0;

public GadgetIterator(Gadget[] gadgetList) {
this.gadgetList = gadgetList;
}

@Override
public boolean hasNext() {
if(position >= gadgetList.length || gadgetList[position] == null){
return false;
}else{
return true;
}

}

@Override
public Object next() {
Gadget gadget = gadgetList[position];
position += 1;
return gadget;
}
}
public class GadgetDirectory {
GadgetCollection gadgetCollection;

public GadgetDirectory(GadgetCollection gadgetCollection) {
this.gadgetCollection = gadgetCollection;
}

public void showGadgets(){
Iterator iterator = gadgetCollection.createIterator();
System.out.println(" ================ Gadgets ============");
while (iterator.hasNext()){
Gadget gadget = (Gadget) iterator.next();
System.out.println(gadget.getName());
}
}
}
public class IteratorClient {

public static void main(String[] args) {
GadgetCollection gadgetCollection = new GadgetCollection();
GadgetDirectory gadgetDirectory = new GadgetDirectory(gadgetCollection);

gadgetDirectory.showGadgets();
}
}

SOLID Principles in this pattern:

  1. You will find Singular Responsibility Principles because you will be able to clean up the client code and the collection by extracting another traversal algorithm into a separate class.
  2. Open Closed Principles. You can add new types of collections and iterators and pass them without breaking the existing code.
  3. We don’t have any fat interface in our system so it supports interface segregation principles. Can you find the other solid principles in this pattern !! Look at it closely.

Relation with other patterns:

Can you combine both the composite and the iterator pattern together?? Yes, you can use this pattern to traverse the composite tree of the composite pattern.

Reference:

  1. https://www.geeksforgeeks.org/iterator-pattern/
  2. Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Design patterns: elements of reusable object-oriented software. Addison-Wesley Professional, 1995.

--

--

Abdullah Al Noman

Software Engineer | High Integrity System Graduate @Frankfurt University of Applied Sciences