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.
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!