Bird
0
0
LLDsystem_design~7 mins

Iterator pattern in LLD - System Design Guide

Choose your learning style9 modes available
Problem Statement
When a collection's internal structure is exposed directly, clients can accidentally modify it or become tightly coupled to its implementation. This makes the code fragile and hard to maintain, especially when the collection changes internally.
Solution
The iterator pattern provides a way to access elements of a collection sequentially without exposing its underlying representation. It defines a separate iterator object that handles traversal, allowing clients to iterate safely and uniformly over different collection types.
Architecture
┌───────────────┐       ┌───────────────┐       ┌───────────────┐
│   Client      │──────▶│   Iterator    │──────▶│   Collection  │
│ (uses next()) │       │ (next(), hasNext())│   │ (data storage)│
└───────────────┘       └───────────────┘       └───────────────┘

This diagram shows the client using an iterator to traverse a collection without accessing its internal structure directly.

Trade-offs
✓ Pros
Encapsulates traversal logic, keeping collection implementation hidden.
Supports multiple traversal algorithms without changing the collection.
Simplifies client code by providing a uniform interface for iteration.
✗ Cons
Adds extra classes and objects, increasing code complexity.
May introduce slight performance overhead due to additional abstraction.
Requires careful design to handle concurrent modifications safely.
Use when you need to traverse different types of collections uniformly or want to hide the internal structure of collections from clients.
Avoid when collections are simple and direct access is sufficient, or when performance is critical and the overhead of iterator objects is unacceptable.
Real World Examples
Java (Oracle)
Java's Collection Framework uses the Iterator pattern to allow clients to traverse lists, sets, and other collections uniformly without exposing internal data structures.
Python
Python's iterator protocol enables for-loops to traverse various data types like lists, tuples, and generators without exposing their internal implementations.
C++ (STL)
The Standard Template Library uses iterators to provide a common interface for traversing containers like vectors, lists, and maps.
Code Example
Before applying the Iterator pattern, the client accesses the collection's internal list directly, which couples client code to the data structure. After applying the pattern, the Numbers class provides an iterator object that handles traversal, allowing the client to iterate without knowing the internal details.
LLD
### Before (without Iterator pattern):
class Numbers:
    def __init__(self):
        self.data = [1, 2, 3, 4, 5]

# Client accesses internal data directly
nums = Numbers()
for i in range(len(nums.data)):
    print(nums.data[i])


### After (with Iterator pattern):
class Numbers:
    def __init__(self):
        self.data = [1, 2, 3, 4, 5]

    def __iter__(self):
        return NumbersIterator(self.data)

class NumbersIterator:
    def __init__(self, data):
        self._data = data
        self._index = 0

    def __next__(self):
        if self._index < len(self._data):
            result = self._data[self._index]
            self._index += 1
            return result
        else:
            raise StopIteration

    def __iter__(self):
        return self

# Client uses iterator without accessing internal data
nums = Numbers()
for num in nums:
    print(num)
OutputSuccess
Alternatives
Cursor
Cursor exposes the position within the collection and allows modification during traversal, unlike Iterator which focuses on read-only traversal.
Use when: Choose Cursor when you need to modify the collection during iteration.
Enumeration
Enumeration is an older pattern that only supports forward traversal and lacks removal capability, unlike Iterator which supports more operations.
Use when: Choose Enumeration only for legacy systems requiring simple forward traversal.
Summary
The Iterator pattern separates traversal logic from the collection, hiding internal structure.
It provides a uniform way to access elements sequentially across different collection types.
This pattern improves code maintainability and flexibility by decoupling clients from data storage details.