Шаблон Итератор обеспечивает последовательный доступ ко всем элементам коллекции, не раскрывая при этом её внутренней реализации. Задача итератора – упростить обход и сделать его однообразным для коллекций различных типов. Причём реализация шаблона может находиться как в объекте, представляющим коллекции, так и отдельно от него.
В шаблоне Итератор задействованы следующие участники. Интерфейс итератора определяет методы для доступа к элементам коллекций. Итератор – класс, реализующий интерфейс итератора для конкретной коллекции. Интерфейс составного объекта (коллекции) задаёт способ получения итератора клиентом. Наконец, составной объект – это реализация интерфейса коллекции.
Обычно интерфейс итератора состоит из следующих операций:
Reset() – устанавливает первый элемент коллекции в качестве текущего;
MoveNext() – переход на следующий элемент;
IsDone – проверяет, есть ли ещё элементы в коллекции;
Current – возвращает текущий элемент.
Этот список можно изменять. Например, объединить MoveNext() и IsDone в один метод. Или добавить метод Skip(), позволяющий пропустить заданное число элементов. В некоторых случаях может быть полезно свойство, содержащее ссылку на предыдущий элемент.
|
|
Разберём пример реализации шаблона Итератор. Вначале опишем интерфейс итератора:
public interface IIterator<out T>
{
void Reset();
void MoveNext();
bool IsDone { get; }
T Current { get; }
}
Далее представим интерфейс коллекции:
public interface IContainer<out T>
{
IIterator<T> CreateIterator();
}
Сконструируем коллекцию, реализующую интерфейс IContainer<T>. При помощи вложенного класса реализуем итератор коллекции:
public class ListContainer: IContainer<int>
{
private readonly int[] _list;
public class ForwardIterator: IIterator<int>
{
private readonly int[] _iteratorList;
private int _position;
public ForwardIterator(int[] list)
{
_iteratorList = new int[list.Length];
list.CopyTo(_iteratorList, 0);
}
public void Reset()
{
_position = 0;
}
public void MoveNext()
{
_position++;
}
public bool IsDone
{
get { return _position > _iteratorList.Length - 1; }
}
public int Current
{
get { return _iteratorList[_position]; }
}
}
public ListContainer(params int[] data)
{
_list = new int[data.Length];
data.CopyTo(_list, 0);
}
public IIterator<int> CreateIterator()
{
return new ForwardIterator(_list);
}
}
Применить описанные классы и интерфейсы можно следующим образом:
IContainer<int> list = new ListContainer(2, 3, 5, 7);
var iterator = list.CreateIterator();
while (!iterator.IsDone)
{
Console.WriteLine(iterator.Current);
iterator.MoveNext();
}
Поддержка итераторов реализована на платформе.NET и в синтаксисе языка C# при помощи интерфейсов IEnumerable и IEnumerator, операторов yield и foreach. При этом IEnumerator играет роль интерфейса итератора, а IEnumerable выступает в качестве интерфейса составного объекта.