Catalog / Behavioral Patterns / Iterator Pattern
BEHAVIORAL

Iterator Pattern

Access the elements of an aggregate object sequentially without exposing its underlying representation.

Intent & Objective

Provide a uniform way to traverse elements of a complex collection (list, tree, graph) without exposing its internal representation (linked list pointers, hash buckets, binary tree nodes).

👥 Real-World Human Analogies & Social Roles
2 Intuitive Scenarios
Historic City Guidebook Tourism & Travel

"A walking tour provides sequential instructions ('Go here, then next, then next') without requiring you to study the city’s complex sewer and electrical grid."

TV Channel Surfing Broadcasting

"Pressing the 'Next Channel' button scrolls through broadcast stations sequentially without needing to know antenna frequencies."

The Problem

Exposing internal collection mechanics to client code, making it impossible to switch collection types without rewriting client loops.

The Solution

Extract the traversal behavior of a collection into a separate object called an iterator with standard `hasNext()` and `next()` methods.

Key Participants & Architectural Roles

Iterator Interface
Declares operations required for traversing a collection (`next()`, `hasMore()`)
Concrete Iterator
Implements specific traversal algorithm for a collection
Iterable Interface
Declares methods for getting iterators compatible with the collection

Code Samples (Traditional OOP vs Functional Programming)

Available in C++, Python, and Java

Paradigm Contrast: Traditional OOP vs Functional / Data-Oriented

In OOP, Iterator uses explicit stateful iterator objects with `next()` and `hasNext()`. In Functional Programming, Iterators are replaced by pure generators, lazy streams, and higher-order fold/map/filter functions.

Advantages

  • ✓ Single Responsibility Principle: cleans up client code and collections by moving traversal algorithms into separate classes
  • ✓ Open/Closed Principle: implements new types of collections and iterators without breaking existing code
  • ✓ Can iterate over the same collection in parallel

Trade-offs

  • ✗ Overkill for simple arrays or flat lists

When to Apply

  • → When your collection has a complex data structure under the hood, but you want to hide its complexity from clients
  • → To reduce duplication of traversal code across your app

When to Avoid

  • ! When iterating over standard contiguous linear memory buffers