
Итератор на C#
Итератор — это поведенческий паттерн, позволяющий последовательно обходить сложную коллекцию, без раскрытия деталей её реализации.
Благодаря Итератору, клиент может обходить разные коллекции одним и тем же способом, используя единый интерфейс итераторов.
Сложность:
Популярность:
Применимость: Паттерн можно часто встретить в C#-коде, особенно в программах, работающих с разными типами коллекций, и где требуется обход разных сущностей.
Признаки применения паттерна: Итератор легко определить по методам навигации (например, получения следующего/предыдущего элемента и т. д.). Код использующий итератор зачастую вообще не имеет ссылок на коллекцию, с которой работает итератор. Итератор либо принимает коллекцию в параметрах конструктора при создании, либо возвращается самой коллекцией.
Концептуальный пример
Этот пример показывает структуру паттерна Итератор, а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
Program.cs: Пример структуры паттерна
using System; using System.Collections; using System.Collections.Generic; namespace RefactoringGuru.DesignPatterns.Iterator.Conceptual { abstract class Iterator : IEnumerator { object IEnumerator.Current => Current(); // Возвращает ключ текущего элемента public abstract int Key(); // Возвращает текущий элемент. public abstract object Current(); // Переходит к следующему элементу. public abstract bool MoveNext(); // Перематывает Итератор к первому элементу. public abstract void Reset(); } abstract class IteratorAggregate : IEnumerable { // Возвращает Iterator или другой IteratorAggregate для реализующего // объекта. public abstract IEnumerator GetEnumerator(); } // Конкретные Итераторы реализуют различные алгоритмы обхода. Эти классы // постоянно хранят текущее положение обхода. class AlphabeticalOrderIterator : Iterator { private WordsCollection _collection; // Хранит текущее положение обхода. У итератора может быть множество // других полей для хранения состояния итерации, особенно когда он // должен работать с определённым типом коллекции. private int _position = -1; private bool _reverse = false; public AlphabeticalOrderIterator(WordsCollection collection, bool reverse = false) { this._collection = collection; this._reverse = reverse; if (reverse) { this._position = collection.getItems().Count; } } public override object Current() { return this._collection.getItems()[_position]; } public override int Key() { return this._position; } public override bool MoveNext() { int updatedPosition = this._position + (this._reverse ? -1 : 1); if (updatedPosition >= 0 && updatedPosition < this._collection.getItems().Count) { this._position = updatedPosition; return true; } else { return false; } } public override void Reset() { this._position = this._reverse ? this._collection.getItems().Count - 1 : 0; } } // Конкретные Коллекции предоставляют один или несколько методов для // получения новых экземпляров итератора, совместимых с классом коллекции. class WordsCollection : IteratorAggregate { List<string> _collection = new List<string>(); bool _direction = false; public void ReverseDirection() { _direction = !_direction; } public List<string> getItems() { return _collection; } public void AddItem(string item) { this._collection.Add(item); } public override IEnumerator GetEnumerator() { return new AlphabeticalOrderIterator(this, _direction); } } class Program { static void Main(string[] args) { // Клиентский код может знать или не знать о Конкретном Итераторе // или классах Коллекций, в зависимости от уровня косвенности, // который вы хотите сохранить в своей программе. var collection = new WordsCollection(); collection.AddItem("First"); collection.AddItem("Second"); collection.AddItem("Third"); Console.WriteLine("Straight traversal:"); foreach (var element in collection) { Console.WriteLine(element); } Console.WriteLine("\nReverse traversal:"); collection.ReverseDirection(); foreach (var element in collection) { Console.WriteLine(element); } } } }
Output.txt: Результат выполнения
Straight traversal: First Second Third Reverse traversal: Third Second First