Python Iterator Design Pattern

1. Definition

The Iterator Design Pattern provides a way to access the elements of a collection object in a sequential manner without exposing its underlying representation. It involves creating an iterator object that encapsulates the details of traversing the collection.

2. Problem Statement

Imagine having a collection, such as a list or a tree. You want to traverse its items without needing to know how they're stored or having to expose the collection's internal structure. Moreover, you might want to provide different ways of traversing the same collection.

3. Solution

Define an Iterator interface with methods for accessing the current element and checking if there's a next element. Then, for each type of collection, provide a concrete iterator that implements this interface. The client can then use the iterator to traverse the collection without knowing its internals.

4. Real-World Use Cases

1. Traversing items in a playlist.

2. Navigating through pages in a book.

3. Iterating over elements in data structures like lists, trees, and graphs.

5. Implementation Steps

1. Define the Iterator interface with methods: __iter__(), __next__().

2. Implement a concrete iterator for the specific collection.

3. The collection object should have a method to return its iterator.

6. Implementation in Python

# Iterator Interface and Concrete Iterator
class Iterator:
    def __iter__(self):
        return self
    def __next__(self):
        pass
class ConcreteIterator(Iterator):
    def __init__(self, collection):
        self._collection = collection
        self._index = 0
    def __next__(self):
        if self._index < len(self._collection):
            value = self._collection[self._index]
            self._index += 1
            return value
        else:
            raise StopIteration
# Collection with Iterator
class ConcreteCollection:
    def __init__(self):
        self._items = []
    def __iter__(self):
        return ConcreteIterator(self._items)
    def add_item(self, item):
        self._items.append(item)
# Client code
collection = ConcreteCollection()
collection.add_item("Item 1")
collection.add_item("Item 2")
collection.add_item("Item 3")
for item in collection:
    print(item)

Output:

Item 1
Item 2
Item 3

Explanation:

1. The Iterator interface is defined with the necessary methods for iteration.

2. ConcreteIterator is an implementation of the Iterator interface for our specific collection. It tracks its position and provides the next item on demand.

3. The ConcreteCollection is a sample collection that uses the iterator for traversal. It contains a list of items and returns its iterator when iterated over.

4. In the client code, items are added to the collection and then traversed using a for loop, demonstrating the iterator's functionality.

7. When to use?

The Iterator Pattern is useful when:

1. You want to provide a uniform way to access different collections.

2. The internal representation of a collection should be hidden from its clients.

3. You need to provide multiple ways to traverse a collection.


Comments