Introduction

Imagine you are building a music streaming application.

A playlist contains hundreds of songs.

Users should be able to:

  • Play the next song

  • Check if more songs exist

  • Restart the playlist

  • Traverse songs one by one

A beginner might directly access the internal collection:


This works fine.

But what if later the internal storage changes?

Instead of a vector, you decide to use:

  • Linked List

  • Tree

  • Hash Table

  • Database Cursor

Now every piece of code accessing the collection must change.

This creates tight coupling between the client and the collection implementation.

The Iterator Design Pattern solves this problem.

It provides a standardized way to traverse a collection without exposing how the collection is internally stored.

What is the Iterator Pattern?

The Iterator Pattern is a behavioral design pattern that provides a way to access elements of a collection sequentially without exposing its internal representation.

In simple words:

Iterator allows clients to traverse a collection without knowing how the collection is implemented internally.

The client only knows how to move through elements.

It does not know whether the data is stored in:

  • Arrays

  • Linked Lists

  • Trees

  • Graphs

  • Databases

Real World Analogy

Imagine visiting an art gallery.

The gallery contains many paintings.

As a visitor, you simply move:

  • To the next painting

  • To the previous painting

  • Check if more paintings exist

You don't need to know:

  • How paintings are stored

  • How rooms are organized

  • How inventory is maintained

The gallery guide acts like an iterator.

It provides a simple way to navigate through the collection.

Why Do We Need the Iterator Pattern?

Suppose we have a playlist class.


Client code:


At first, this seems reasonable.

But several problems appear.

Problems Without the Iterator Pattern

1. Internal Structure Is Exposed

The client directly accesses:

vector<string>

The internal implementation becomes public knowledge.

2. Tight Coupling

If storage changes:

vector → linked list

Client code may break.

3. Multiple Traversal Logic

Different clients may implement traversal differently.

This creates duplicate code.

4. Violates Encapsulation

Collections should manage their own traversal behavior.

Clients should not know internal details.

Solution: Iterator Pattern

The Iterator Pattern separates:

  • Collection Storage

  • Collection Traversal

The collection stores data.

The iterator handles traversal.

Now clients only interact with the iterator.

Key Components of the Iterator Pattern

The Iterator Pattern usually contains:

1. Iterator Interface

Defines traversal operations.

Example:

next()
hasNext()

2. Concrete Iterator

Implements traversal logic.

3. Aggregate Interface

Represents the collection.

4. Concrete Aggregate

Actual collection implementation.

Structure of the Iterator Pattern

Collection
     │
     ▼
 Create Iterator
     │
     ▼
 Iterator
     │
 ┌───┴───┐
 │       │
next() hasNext()

Example: Playlist Traversal

Let's build a simple playlist system.

Step 1: Create Iterator Interface


Step 2: Create Playlist Collection


Step 3: Create Concrete Iterator


Step 4: Client Code


Output

Song A
Song B
Song C

How the Iterator Pattern Works

Let's understand the flow.

Step 1

The collection stores data.

playlist.addSong(...)

Step 2

An iterator is created.

PlaylistIterator iterator(...)

Step 3

Client asks:

hasNext()

Step 4

An iterator returns elements one by one.

next()

The client never directly accesses internal storage.

Better Version Using Aggregate Interface

In real systems, collections usually create their own iterators.

Example:


Collection:


Client:


This further hides implementation details.

Internal Iterator vs External Iterator

A common interview topic.

External Iterator

The client controls traversal.

Example:


The client decides when to move.

Internal Iterator

The collection controls traversal.

Example:

playlist.forEach(...)

The collection decides how traversal occurs.

Modern programming languages often use internal iterators.

Iterator in STL

The C++ STL heavily uses the Iterator Pattern.

Example:


Here:

begin()
end()
iterator

are implementations of the Iterator Pattern.

This is one of the most practical examples of the pattern.

Advantages of the Iterator Pattern

1. Encapsulation

Internal collection structure remains hidden.

2. Loose Coupling

Clients do not depend on collection implementation.

3. Reusable Traversal Logic

Traversal code exists in one place.

4. Multiple Traversal Strategies

Different iterators can provide different traversals.

Example:

Forward Iterator
Reverse Iterator
Random Iterator

5. Cleaner Client Code

Clients focus on business logic rather than traversal details.

Disadvantages of the Iterator Pattern

1. Additional Classes

The pattern introduces extra objects.

2. Slightly Increased Complexity

Simple collections may not need custom iterators.

3. Performance Overhead

Very large systems may experience minor overhead due to abstraction.

Multiple Iterators for Same Collection

One powerful feature is creating multiple traversal methods.

Example:

Playlist:

Song A
Song B
Song C
Song D

Possible iterators:

Forward Iterator

A → B → C → D
Reverse Iterator

D → C → B → A
Shuffle Iterator

B → D → A → C

The collection remains unchanged.

Only traversal behavior changes.

Iterator vs Direct Access

Direct AccessIterator Pattern
Exposes storageHides storage
Tight couplingLoose coupling
Traversal logic repeatedTraversal logic centralized
Difficult to change storageEasy to change storage
Less flexibleMore flexible

Iterator vs Observer

This is a common interview question.

IteratorObserver
Traverses collectionsNotifies objects
Accesses elements one by oneSends updates to subscribers
Focuses on navigationFocuses on communication
Pull-basedPush-based

Real World Applications

The Iterator Pattern is widely used in:

  • STL Containers

  • Java Collections Framework

  • Database cursors

  • File system traversal

  • Tree traversal

  • Graph traversal

  • Playlist navigation

  • Browser history navigation

  • Pagination systems

Almost every collection framework internally uses iterators.

Common Beginner Mistakes

1. Exposing Internal Collections

Avoid:

vector<string>& getSongs()

Whenever possible.

Use iterators instead.

2. Mixing Traversal with Collection Logic

Collections should store data.

Iterators should traverse data.

3. Ignoring Boundary Conditions

Always check:

hasNext()

before:

next()

4. Creating One Iterator for Every Need

Sometimes standard iterators are sufficient.

Avoid unnecessary complexity.

Simple Visualization

Without Iterator:

Client
   │
   ▼
Collection Internals

The client directly depends on storage details.

With Iterator:

Client
   │
   ▼
Iterator
   │
   ▼
Collection

The iterator acts as a bridge between the client and the collection.

Summary

The Iterator Design Pattern provides a standardized way to traverse collections without exposing their internal structure.

Separating traversal logic from storage logic, it improves encapsulation, flexibility, and maintainability. Clients interact with iterators instead of directly accessing collection internals, making it easier to change storage implementations without affecting existing code.

Whenever you need to traverse elements of a collection while keeping its internal implementation hidden, the Iterator Pattern offers a clean and scalable solution.