DEV Community

Cover image for Design Patterns Simplified: Part 20 — Iterator Pattern (a.k.a. “The Product Browser”)
Prateek Prabhakar
Prateek Prabhakar

Posted on • Edited on • Originally published at Medium

Design Patterns Simplified: Part 20 — Iterator Pattern (a.k.a. “The Product Browser”)

The Iterator Pattern belongs to the Behavioral category of design patterns.
Why? Because it is all about how you access elements in a collection without exposing its internal structure.

Imagine you are at a buffet. Cravings!!!
You don’t really care how dishes are stored in the kitchen or in which order the chef cooked them. You simply move along the buffet line and take one dish after another.

That’s what the Iterator Pattern does for collections in code. It lets you move through items sequentially without knowing how they are actually stored (array, tree, linked list, etc.).


The E-commerce Product Catalog

Suppose you are building a product catalog for an online store. The catalog might store products in different ways, maybe an array, maybe a list fetched from a database, or even a cache.

The challenge? You want to give customers a consistent browsing experience without caring about the underlying storage.
In comes the iterator pattern to help you out.

What Is the Iterator Pattern?

This pattern provides a way to sequentially access elements of a collection without exposing how the collection is implemented.
So, instead of writing different loops for arrays, lists, or DB queries, you just ask the iterator,

HasNext() → Is there another product?
Next() → Show me the next product.

What Does the Code Look Like?

// Step 1: Define a Product class
Class Product
    Property name
    Property price

    Constructor(name, price)
        this.name = name
        this.price = price

// Step 2: Define the Iterator interface
Interface Iterator
    Method HasNext() : Boolean
    Method Next() : Product

// Step 3: Concrete Iterator for a List of Products
Class ProductIterator implements Iterator
    Property products
    Property position = 0

    Constructor(products)
        this.products = products

    Method HasNext()
        Return position < products.Count

    Method Next()
        product = products[position]
        position = position + 1
        Return product

// Step 4: Define Collection Interface
Interface ProductCollection
    Method CreateIterator() : Iterator

// Step 5: Concrete Product Catalog
Class OnlineStoreCatalog implements ProductCollection
    Property products = []

    Method AddProduct(product)
        products.Add(product)

    Method CreateIterator()
        Return new ProductIterator(products)

// caller logic
catalog = new OnlineStoreCatalog()
catalog.AddProduct(new Product("Laptop", 800))
catalog.AddProduct(new Product("Headphones", 100))
catalog.AddProduct(new Product("Keyboard", 50))

iterator = catalog.CreateIterator()

While iterator.HasNext()
    product = iterator.Next()
    Print "Browsing product: " + product.name 
       + " ($" + product.price + ")"

Enter fullscreen mode Exit fullscreen mode

Let me explain on what's happening in the code above. We have the below components that work in tandem to help achieve the iterator pattern.

Product → It is a simple class holding product details like name and price.

Iterator interface → A contract that says, “Any iterator must at least know how to check if there is another item (HasNext()) and how to return the next one (Next()).”

ProductIterator → The actual implementation of an iterator for a product list. It keeps track of your current position and knows how to move forward.

ProductCollection interface → Another contract that says, “Any product collection should be able to give an iterator.”

OnlineStoreCatalog → It is the concrete product collection. It stores products internally, but instead of exposing them directly, it gives you an iterator when asked (CreateIterator()).

The end user only interacts with the iterator and not the collection itself. They just keep asking,

“Do you have another product?” → “Okay, give it to me.”

The key here is that the client does not need to know how products are stored (list, array, DB fetch). They only interact with the iterator, which provides a consistent way to browse.

What Did We Achieve?

  • Abstraction: The client does not need to know how products are stored, they can simply iterate over them.
  • Consistency: A uniform way to browse products, regardless of underlying data structure.
  • Flexibility: You can change the collection’s implementation (array, DB, API) without touching client code.

When Should You Use Iterator Pattern?

  • When you want a uniform way to traverse different types of collections.
  • When you do not want to expose the internal structure of a collection.
  • When collections might change, but client code should remain stable.

Use Cases?

As you might have already guessed, the Iterator Pattern shows up all around us.

  • E-commerce product catalogs : browse through thousands of products page by page without knowing the storage backend.
  • Social media feeds : scroll through posts, reels, or stories in sequence.
  • Photo gallery apps : swipe through images one by one, regardless of how they’re stored on disk.
  • Music or video playlists : play next, previous, or shuffle without exposing the internal list.
  • File browsing : move through folders and files seamlessly.

To summarize, it would be apt to say,

The Iterator Pattern is like giving your customers a “Next Product” button in your store. They don’t care how the products are stored, instead, they just keep browsing smoothly.

It is one of those patterns that keeps your application user friendly and your code future proof.

Hope this article helped you understand the Iterator Pattern and where to apply effectively.

Next up: Facade Pattern. Stay tuned!


Bonus: Iterator + Composite Pattern - A Perfect Duo

Remember the Composite Pattern we covered earlier (like file/folder structures or org charts)? It helps you organize objects into a hierarchy, where individual items and groups are treated the same.

Now, here’s where Iterator steps in as the perfect partner: it gives you a clean way to walk through that hierarchy.

Take a file–folder system as an example,

  • Composite lets you represent folders that can contain files or even other folders.
  • Iterator then allows you to seamlessly move through these items, whether you are looping through files in one folder or traversing the entire tree.

In short, Composite organizes, Iterator navigates.
Together, they make working with hierarchical data both neat and effortless.

Top comments (0)