Overview
The Iterator Pattern is a behavioral design pattern that provides a way to access elements of a collection (aggregate object) sequentially without exposing its underlying representation. It decouples the traversal logic from the actual collection, allowing flexibility and reusability.
Key Participants
Iterator
Defines the interface for accessing and traversing elements (e.g., hasNext(), next()).
Concrete Iterator
Implements the Iterator interface.
Keeps track of the current position in the traversal of the collection.
Aggregate (Collection)
Defines the interface for creating an iterator (e.g., createIterator()).
Concrete Aggregate
Implements the Aggregate interface.
Stores the collection of elements and creates an iterator to traverse them.
Implementation in Code
Example: Custom Collection of Names
import java.util.List;
import java.util.ArrayList;
// Iterator Interface
interface Iterator<T> {
boolean hasNext();
T next();
}
// Concrete Iterator
class NameIterator implements Iterator<String> {
private List<String> names;
private int position = 0;
public NameIterator(List<String> names) {
this.names = names;
}
@Override
public boolean hasNext() {
return position < names.size();
}
@Override
public String next() {
if (this.hasNext()) {
return names.get(position++);
}
return null;
}
}
// Aggregate Interface
interface Collection<T> {
Iterator<T> createIterator();
}
// Concrete Aggregate
class NameCollection implements Collection<String> {
private List<String> names = new ArrayList<>();
public void addName(String name) {
names.add(name);
}
@Override
public Iterator<String> createIterator() {
return new NameIterator(names);
}
}
// Client
public class IteratorPatternDemo {
public static void main(String[] args) {
NameCollection nameCollection = new NameCollection();
nameCollection.addName("Alice");
nameCollection.addName("Bob");
nameCollection.addName("Charlie");
Iterator<String> iterator = nameCollection.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
Key Methods
hasNext(): Checks if there are more elements in the collection.
next(): Retrieves the next element in the collection.
Advantages
Encapsulation: Hides the internal structure of the collection.
Uniform Traversal: Provides a standard way to traverse collections regardless of their implementation.
Reusability: Iterators can be reused across different collections with consistent interfaces.
Multiple Iterators: Supports multiple iterators to traverse the same collection independently.
Disadvantages
Overhead: Adding iterator logic can increase complexity and memory usage.
Limited Access: Iterators typically provide sequential access, not random access.
Real-World Examples
Java Collections Framework: Iterators for lists, sets, and maps (e.g., Iterator interface in Java).
File Systems: Traversing files and directories in a file system.
Social Media Feeds: Iterating over posts in a timeline or news feed.
When to Use the Iterator Pattern?
When you need a standard way to traverse different types of collections.
When you want to decouple the traversal logic from the collection’s internal structure.
When you need multiple ways to traverse the same collection (e.g., forward, backward).