Шаблон Iterator
Шаблон проектирования Итератор — один из поведенческих паттернов, который позволяет последовательно обходить элементы коллекций различных типов без раскрытия внутренней структуры самой коллекции. Это особенно полезно, когда разные классы предоставляют доступ к своим данным разными способами, но нам важно получать единообразное представление об элементах независимо от типа контейнера.
Когда применяется?
- Необходимо обеспечить последовательный доступ ко всем элементам сложной структуры данных.
- Нужно скрыть внутреннюю реализацию структуры данных от клиентов, предоставляя возможность перебора элементов прозрачно и легко.
- Требуется поддержка нескольких вариантов итерации одной и той же структуры одновременно.
Как устроено?
Основные компоненты шаблона:
- Агрегат: класс, представляющий коллекцию объектов. Агрегат реализует метод
createIterator()
, возвращающий объект класса Итератора, соответствующего данному типу агрегата. - Итератор: интерфейс или абстрактный базовый класс, определяющий методы перемещения между элементами (
next()
), проверки достижения конца последовательности (hasNext()
) и возвращения текущего элемента (current()
). - Конкретный Итератор: реализация интерфейса Итератора для конкретного агрегата. Конкретный итератор хранит внутреннее состояние позиции в агрегации и управляет перемещением по нему.
Пример реализации на PHP:
// Интерфейс Итераторов
interface Iterator {
public function next();
public function hasNext(): bool;
}
// Абстрактная коллекция (агрегат)
abstract class Aggregate {
abstract public function createIterator(): Iterator;
}
// Реализация конкретной коллекции
class ConcreteAggregate extends Aggregate {
private array $items = [];
// Метод создает соответствующий итератор
public function createIterator(): Iterator {
return new ConcreteIterator($this);
}
// Методы добавления/получения элементов коллекции
public function addItem(string $item): void {
$this->items[] = $item;
}
public function getItems(): array {
return $this->items;
}
}
// Конкретный итератор
class ConcreteIterator implements Iterator {
private int $position = 0;
private ConcreteAggregate $aggregate;
public function __construct(ConcreteAggregate $aggregate) {
$this->aggregate = $aggregate;
}
public function next() {
if ($this->hasNext()) {
return $this->aggregate->getItems()[$this->position++];
}
return null;
}
public function hasNext(): bool {
return isset($this->aggregate->getItems()[$this->position]);
}
}
// Пример использования
$collection = new ConcreteAggregate();
$collection->addItem('Элемент 1');
$collection->addItem('Элемент 2');
$collection->addItem('Элемент 3');
$iterator = $collection->createIterator();
while ($iterator->hasNext()) {
echo $iterator->next() . "\n";
}
Преимущества
- Упрощение клиента: клиенту достаточно вызывать стандартные методы итератора, не заботясь о внутреннем устройстве коллекции.
- Возможность поддерживать различные способы обхода одних и тех же структур данных.
- Сокрытие деталей внутреннего устройства агрегатов.
Таким образом, шаблон Итератор помогает абстрагироваться от конкретных реализаций контейнеров и обеспечивает единый способ обработки элементов разных коллекций.