3.5 - Iterator Pattern: Behavioral Design Patterns
The Iterator Pattern is a behavioral design pattern that provides a way to sequentially access the elements of a collection without exposing the underlying structure. It separates the process of traversal from the actual collection, promoting loose coupling between the collection and the client.
The Iterator Pattern is useful when you need to iterate through a collection of objects without knowing its internal structure or implementation details, making it ideal for use with lists, arrays, trees, and more.
Key Components of the Iterator Pattern:
Collection Interface: Declares the methods to add, remove, and create an iterator for the collection.
Concrete Collection: Implements the collection interface and defines how the elements are stored and managed.
Iterator Interface: Declares the methods to traverse elements of a collection.
Concrete Iterator: Implements the iterator interface and provides mechanisms to traverse the specific collection.
Client: Uses the collection and iterator to access the elements.
Code Example
Here’s an implementation of the Iterator Pattern using renamed class and function names for clarity.
1. Collection Interface
The ItemCollection
interface declares methods for adding and removing items from the collection, as well as a method to create an iterator.
// Collection Interface
interface ItemCollection<T> {
void addElement(T element);
void removeElement(T element);
Iterator<T> createIterator();
}
2. Concrete Collection
The ItemList
class implements the ItemCollection
interface and uses an ArrayList
internally to store elements. It also provides functionality to create an iterator for the collection.
// Concrete Collection Class
class ItemList<T> implements ItemCollection<T> {
private List<T> elements = new ArrayList<>();
@Override
public void addElement(T element) {
elements.add(element);
}
@Override
public void removeElement(T element) {
elements.remove(element);
}
@Override
public Iterator<T> createIterator() {
return elements.iterator(); // Using Java's built-in iterator for simplicity
}
}
3. Client
The IteratorDemo
class demonstrates how to use the ItemList
and its iterator to access the elements of the collection.
// Client Class
public class IteratorDemo {
public static void main(String[] args) {
ItemCollection<String> myCollection = new ItemList<>(); // Creating the collection
// Adding elements to the collection
myCollection.addElement("Apple");
myCollection.addElement("Banana");
myCollection.addElement("Cherry");
// Creating an iterator to traverse the collection
Iterator<String> iterator = myCollection.createIterator();
// Using the iterator to access elements
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
Explanation:
ItemCollection Interface: The interface defines three methods—
addElement()
,removeElement()
, andcreateIterator()
. ThecreateIterator()
method returns an iterator for traversing the elements in the collection.ItemList Class: This is the concrete implementation of the
ItemCollection
interface. It uses a list (ArrayList
) to store the elements and provides the necessary methods to add, remove, and create an iterator.Iterator: In this case, we’re using Java’s built-in
Iterator
, which provides the basic functionality for traversing the elements in the collection. The iterator offers methods such ashasNext()
to check if more elements are available andnext()
to access the next element.Client (IteratorDemo): This class demonstrates how the collection and iterator work together. After adding elements to the collection, the client uses the iterator to access and print each element sequentially.
Benefits of the Iterator Pattern:
Decoupling: The iterator pattern decouples the client from the internal structure of the collection. The client does not need to know how the collection is implemented or how elements are stored; it simply uses the iterator to access elements.
Uniform Traversal: Different types of collections (e.g., lists, arrays, trees) can provide their own iterators, allowing clients to traverse them in a uniform manner.
Flexibility: Iterators provide a flexible way to traverse a collection in various ways, such as forward, backward, or even skipping elements, without changing the collection’s structure.
Single Responsibility: The iterator pattern follows the Single Responsibility Principle, as the collection is responsible for storing and managing elements, while the iterator is responsible for traversal.
Real-World Use Cases:
Java Collections: In Java, all the
Collection
classes (e.g.,ArrayList
,HashSet
) use the iterator pattern. TheIterator
interface in Java allows you to iterate over any collection without knowing its specific implementation.File Systems: Iterators can be used to traverse files and directories, providing a way to access files in a file system structure.
Tree Structures: In data structures such as trees, different types of iterators (e.g., pre-order, in-order, post-order) can be used to traverse the nodes.
Conclusion:
The Iterator Pattern is a useful tool when you want to provide a uniform way to traverse different types of collections without exposing their internal implementation. It allows for more flexible and scalable code, as it separates the collection’s responsibility for storing elements from the logic of iterating over them. By using iterators, you can create a clean, maintainable way to access elements in any type of collection.
Subscribe to my newsletter
Read articles from Venu Madhav Emmadi directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by