Close
IteratorPattern
IteratorPattern

Iterator Design Pattern

Introduction

The iterator design pattern states that, if a  collection of items stored in a certain data structure. And if this collection can possibly be traversed in different ways as per client use cases. Then separate each type of traversal logic to its individual class, each of this class should implement a common Iterator interface.

Why do we need iterator pattern?

Collections can range from as simple as list to as complex as graph. With the iterator design pattern the complex representation of the underlying collection is abstracted and the traversal logic can be decoupled from collection representation.

Iterator pattern Internals

Iterator design pattern has four main components

  • Iterator Interface which contains the set of methods that needed to traverse each item in the collection.
  • Concrete Iterator classes implement the iterator interface and supports a single type of traversal.
  • Iterator collection Interface contains methods for each type of traversal. And each of these types shall return Iterator Interface object.
  • Concrete collection Iterator implementation hides the complex representation of the collection and exposes the API to get iterator object of each traversal type.

Requirements of Doubly linked list collection

  • List should be able traverse from forward.
  • List should be able to traverse from backwards.
class diagram Iterator design pattern using DLL collection.

Doubly linked list collection implemented in java

Main.java

import working.example.tech.DesignPattern.Behavioural.IteratorPattern.*;
public class Main {
    public static void main(String[] args) {	
    	DLLClientUser client = new DLLClientUser();
    	client.RunTest();
    }
}

DLLClientUser.java

package working.example.tech.DesignPattern.Behavioural.IteratorPattern;
public class DLLClientUser implements working.example.tech.interfaces.TestCaseRunner {
	@Override
	public void RunTest() {
		// TODO Auto-generated method stub
		DLL dll = new DLL();
		dll.addNode(1);
		dll.addNode(2);
		dll.addNode(3);
		dll.addNode(4);
		dll.addNode(5);
		
		System.out.println("Iterating DLL items using forward Iterator");
		IteratorIntf fItr = dll.forwardDLLIterator();
		DLL.Node node = fItr.hasNext(); 
		while ( node != null) {
			System.out.println(node.data);
			node = fItr.hasNext();
		}
		
		System.out.println("Iterating DLL items using Backward Iterator");
		System.out.println();
		IteratorIntf bItr = dll.backwardDLLiterator();
		node = bItr.hasNext(); 
		while ( node != null) {
			System.out.println(node.data);
			node = bItr.hasNext();
		}
	}
	@Override
	public void showOut() {
		// TODO Auto-generated method stub
		
	}
}

DLL.java

package working.example.tech.DesignPattern.Behavioural.IteratorPattern;
public class DLL implements IterableCollectionIntf{
   Node head;
   Node tail;
   
   public class Node {
	  int data;
	  Node next;
	  Node prev;
	  
	  Node (int data) {
	   this.data = data;
	   this.prev = null;
	   this.next = null;
	  }
	  
	  Node (int data, Node nxt, Node prv) {
	   this.data = data;
	   this.next = nxt;
	   this.prev = prv;
	  }
   }
   
   void addNode(int data) {
	   Node node = new Node(data);
	   if (head == null) {
		   head = node;
		   tail = node;
	   } else {
		   node.prev = tail;
		   tail.next = node;
		   tail = node;
	   }
   }
	@Override
	public IteratorIntf forwardDLLIterator() {
		// TODO Auto-generated method stub
		return new ForwardIterator(head);
	}
	@Override
	public IteratorIntf backwardDLLiterator() {
		// TODO Auto-generated method stub
		return new BackwardIterator(tail);
	}
}

IteratorIntf.java

package working.example.tech.DesignPattern.Behavioural.IteratorPattern;
public interface IteratorIntf {
  DLL.Node hasNext();
}

ForwardIterator.java

package working.example.tech.DesignPattern.Behavioural.IteratorPattern;
import working.example.tech.DesignPattern.Behavioural.IteratorPattern.DLL.Node;
public class ForwardIterator implements IteratorIntf{
    DLL.Node start;
    
    ForwardIterator(DLL.Node in) {
    	start = in;
    }
    
	@Override
	public Node hasNext() {
		DLL.Node temp = null;
		if (start != null) {
		   temp = start;
		   start = start.next;
		}
		return temp;
	}
}

BackwardIterator.java

package working.example.tech.DesignPattern.Behavioural.IteratorPattern;
import working.example.tech.DesignPattern.Behavioural.IteratorPattern.DLL.Node;
public class BackwardIterator implements IteratorIntf {
    DLL.Node end;
    
	BackwardIterator(DLL.Node in) {
		end = in;
	}
	
	@Override
	public Node hasNext() {
		DLL.Node temp = null;
		if (end != null) {
		   temp = end;
		   end = end.prev;
		}
		return temp;
	}
}

IterableCollectionIntf.java

package working.example.tech.DesignPattern.Behavioural.IteratorPattern;
public interface IterableCollectionIntf {
	 IteratorIntf forwardDLLIterator();
	 IteratorIntf backwardDLLiterator();
}

Conclusion

This blog covered the iterator design pattern with its advantages. Hope this shall help in your upcoming features. Stay tuned for more!

More blogs