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.
### 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)