Ответ
Паттерн «Итератор» — это поведенческий паттерн, который предоставляет способ последовательного доступа к элементам составного объекта (коллекции, дерева, графа), не раскрывая его внутреннего представления.
Основная цель: Отделить алгоритм обхода коллекции от самой коллекции, что позволяет иметь разные алгоритмы обхода и делает клиентский код независимым от структуры данных.
Ключевые компоненты:
IIterator<T>— интерфейс итератора с методамиMoveNext(),Currentи, возможно,Reset().IAggregate<T>/IEnumerable<T>— интерфейс агрегата (коллекции), который может создавать итератор (методGetEnumerator()).- Конкретный итератор (Concrete Iterator) — реализует логику обхода конкретной коллекции.
- Конкретная коллекция (Concrete Aggregate) — возвращает экземпляр конкретного итератора.
Пример реализации на C#:
// Пользовательский итератор для обхода коллекции в обратном порядке
public class ReverseIterator<T> : IIterator<T>
{
private readonly List<T> _collection;
private int _currentPosition;
public ReverseIterator(List<T> collection)
{
_collection = collection;
_currentPosition = collection.Count - 1;
}
public bool MoveNext() => _currentPosition >= 0;
public T Current => _collection[_currentPosition--];
}
// Пользовательская коллекция
public class MyCollection<T> : IAggregate<T>
{
private List<T> _items = new List<T>();
public void Add(T item) => _items.Add(item);
// Стандартный итератор (foreach)
public IEnumerator<T> GetEnumerator() => _items.GetEnumerator();
// Специальный итератор (обратный порядок)
public IIterator<T> GetReverseIterator() => new ReverseIterator<T>(_items);
}
// Использование
var collection = new MyCollection<int> { 1, 2, 3, 4, 5 };
Console.WriteLine("Standard iteration:");
foreach (var item in collection) Console.Write(item + " "); // 1 2 3 4 5
Console.WriteLine("nReverse iteration:");
var reverseIterator = collection.GetReverseIterator();
while (reverseIterator.MoveNext())
{
Console.Write(reverseIterator.Current + " "); // 5 4 3 2 1
}
Встроенная поддержка в .NET:
Паттерн глубоко интегрирован в язык C# через интерфейсы IEnumerable<T> и IEnumerator<T>. Ключевое слово foreach — это синтаксический сахар для работы с итератором.
// Внутренняя работа foreach
IEnumerator<int> enumerator = collection.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
int item = enumerator.Current;
// ... работа с item
}
}
finally
{
enumerator.Dispose();
}
Преимущества:
- Единый интерфейс обхода: Клиентский код работает с любыми коллекциями через единый интерфейс итератора.
- Принцип единой ответственности: Коллекция отвечает за хранение данных, итератор — за логику обхода.
- Параллельный обход: Можно создать несколько независимых итераторов для одной коллекции.
- Отложенное выполнение (yield return): В C# с помощью
yield returnможно создавать итераторы с ленивым выполнением, что эффективно для работы с большими или генерируемыми на лету данными.