В разделе «Структура» шаблона проектирования Итератор книга Шаблоны проектирования: элементы многоразового объектно-ориентированного программного обеспечения определяет Iterator
класс с четырьмя основными операциями: First
, Next
, IsDone
и CurrentItem
.
В разделе «Реализация» книга содержит следующий элемент :
Кто определяет алгоритм обхода? Итератор - не единственное место, где можно определить алгоритм обхода. Агрегат может определять алгоритм обхода и использовать итератор для хранения только состояния итерации. Мы называем этот тип итератора курсор , так как он просто указывает на текущую позицию в совокупности. Клиент вызовет операцию Next
в агрегате с курсором в качестве аргумента, а операция Next
изменит состояние курсора.
Если итератор отвечает за алгоритм обхода, тоЛегко использовать разные алгоритмы итерации в одном агрегате, а также проще использовать один и тот же алгоритм в разных агрегатах. С другой стороны, алгоритму обхода может потребоваться доступ к закрытым переменным агрегата. В этом случае размещение алгоритма обхода в итераторе нарушает инкапсуляцию агрегата.
Но примерная реализация итератора курсора не предоставляется.
Кто должен предоставлять интерфейс для управления итерацией, итератором курсора или агрегатом?
Ниже приведен пример реализации двух альтернатив в Python.
Если итератор курсора предоставляет интерфейс итерации, в дополнение к операциям GetState
и SetState
он должен определять First
, Next
, IsDone
и CurrentItem
базовые операции и делегирование соответствующим агрегатным операциям:
class Iterator:
def __init__(self, aggregate):
self.__aggregate = aggregate
def first(self):
self.__aggregate._first(self)
def next(self):
self.__aggregate._next(self)
def is_done(self):
return self.__aggregate._is_done(self)
def current_item(self):
return self.__aggregate._current_item(self)
def _get_state(self):
return self.__state
def _set_state(self, state):
self.__state = state
И агрегат должен определять те же базовые операции, которые извлекают и обновляют состояние итератора курсора, используя его операции GetState
и SetState
:
class Aggregate:
def __init__(self, list):
self.__list = list
def _first(self, iterator):
iterator._set_state(0)
def _next(self, iterator):
iterator._set_state(iterator._get_state() + 1)
def _is_done(self, iterator):
return iterator._get_state() >= len(self.__list)
def _current_item(self, iterator):
if self._is_done(iterator):
raise ValueError
return self.__list[iterator._get_state()]
def create_iterator(self):
return Iterator(self)
Затем клиент будет использовать итератор курсора для управления итерацией:
aggregate = Aggregate(["foo", "bar", "baz", "qux"])
iterator = aggregate.create_iterator()
iterator.first()
while not iterator.is_done():
print(iterator.current_item())
iterator.next()
Если совокупность предоставляет tВ итерационном интерфейсе итератор курсора должен определять операции GetState
и SetState
:
class Iterator:
def _get_state(self):
return self.__state
def _set_state(self, state):
self.__state = state
И агрегат должен определять First
, Next
, IsDone
и CurrentItem
basicоперации, которые извлекают и обновляют состояние итератора курсора, используя его операции GetState
и SetState
:
class Aggregate:
def __init__(self, list):
self.__list = list
def first(self, iterator):
iterator._set_state(0)
def next(self, iterator):
iterator._set_state(iterator._get_state() + 1)
def is_done(self, iterator):
return iterator._get_state() >= len(self.__list)
def current_item(self, iterator):
if self.is_done(iterator):
raise ValueError
return self.__list[iterator._get_state()]
def create_iterator(self):
return Iterator()
Затем клиент будет использовать агрегат для управления итерацией:
aggregate = Aggregate(["foo", "bar", "baz", "qux"])
iterator = aggregate.create_iterator()
aggregate.first(iterator)
while not aggregate.is_done(iterator):
print(aggregate.current_item(iterator))
aggregate.next(iterator)