Шаблон проектирования итератора — это широко используемый шаблон, обеспечивающий очень полезную абстракцию. Шаблон итератора используется для доступа и обхода элементов коллекции без необходимости понимания или раскрытия базовой структуры коллекции.

Итератор — это поведенческий шаблон проектирования, в котором вы используете итератор для последовательного перечисления элементов контейнера, то есть коллекции. Поведенческие шаблоны проектирования — это те, которые управляют совместной работой объектов и делегированием ответственности между объектами.

Одним из преимуществ шаблона итератора является то, что он позволяет изменять реализацию коллекции, не изменяя способ доступа к коллекции извне.

В этой статье мы рассмотрим простую реализацию шаблона проектирования итератора с использованием C#. Участниками типичной реализации шаблона итератора являются:

  1. Iterator. Обычно это интерфейс (или абстрактный класс), который определяет интерфейс для обхода элементов контейнера.
  2. ConcreteIterator. Это класс, реализующий интерфейс Iterator.
  3. Aggregate. Обычно это абстрактная коллекция, определяющая интерфейс для создания экземпляра итератора.
  4. ConcreteAggregate. Это класс, который реализует Aggregate и возвращает экземпляр конкретного итератора.

Создать коллекцию

Давайте начнем. Сначала создайте проект консольного приложения в Visual Studio. Затем создайте следующий класс с именем Author.

public class Author
    {
        private string firstName, lastName;
        public Author(string firstName, string lastName)
        {
            this.firstName = firstName;
            this.lastName = lastName;
        }
        public string Name
        {
            get { return this.firstName + “\t”+ this.lastName; }
        }
    }

Обратите внимание, что класс Author представляет коллекцию, которую мы хотим сохранить внутри контейнера, а затем выполнить итерацию. Класс Author содержит конструктор параметров, который принимает два аргумента, то есть имя и фамилию автора. Свойство Name класса Author возвращает полное имя автора.

Создайте интерфейс абстрактного контейнера

Вот интерфейс абстрактного контейнера с именем IAbstractContainer. Этот интерфейс содержит объявление метода CreateIterator().

public interface IAbstractContainer
    {
        Iterator CreateIterator();
    }

Реализовать контейнер

Класс Container расширяет интерфейс IAbstractContainer и реализует метод CreateIterator(). Он также содержит свойство Count, которое возвращает количество элементов в коллекции Author. Также есть индексатор. Мы будем использовать индексатор для извлечения данных из коллекции позже.

public class Container : IAbstractContainer
    {
        private List<Author> authors = new List<Author>();
        public Iterator CreateIterator()
        {
            return new Iterator(this);
        }
        public int Count
        {
            get { return authors.Count; }
        }
        public Author this[int index]
        {
            get { return authors[index]; }
            set { authors.Add(value); }
        }
    }

Создайте абстрактный итератор

Следующим в нашем списке типов для реализации является абстрактный итератор. Интерфейс IAbstractIterator содержит объявление операций, которые будет реализовывать конкретный класс итератора.

public interface IAbstractIterator
    {
        Author FirstItem();
        Author NextItem();
        bool IsDone { get; }
    }

Реализовать итератор

Класс Iterator расширяет интерфейс IAbstractIterator. Iterator используется для инкапсуляции реализации итерации коллекции. Обратите внимание, как он использует индекс для отслеживания процесса итерации.

public class Iterator : IAbstractIterator
    {
        private Container aggregate;
        private int currentIndex = 0;
        private int increment = 1;
        public Iterator(Container container)
        {
            aggregate = container;
        }
        public Author FirstItem()
        {           
           currentIndex = 0;
           return aggregate[currentIndex];
        }
        public Author NextItem()
        {
            currentIndex += increment;
            if (!IsDone)
                return aggregate[currentIndex] as Author;
           return null;
        }
        public bool IsDone
        {
            get
            {
                if (currentIndex >= aggregate.Count)
                    return true;
                return false;
            }          
        }
    }

Итерация по элементам коллекции

Наконец, мы создадим экземпляр контейнера, сохраним объекты в контейнере, а затем пройдемся по элементам коллекции. В приведенном ниже фрагменте кода обратите внимание, как мы создаем пять экземпляров класса Author, присваиваем значения свойствам firstName и lastName, а затем создаем экземпляр Iterator, вызывая метод CreateIterator() для экземпляра контейнера.

static void Main(string[] args)
        {
            Container container = new Container();
            container[0] = new Author(“Joydip”, “Kanjilal”);
            container[1] = new Author(“Michael”, “Stevens”);
            container[2] = new Author(“Steve”, “Jones”);
            container[3] = new Author(“Steve”, “Smith”);
            container[4] = new Author(“Jack”, “Gibbs”);
            Iterator iterator = container.CreateIterator();
            for (Author item = iterator.FirstItem(); !iterator.IsDone; item = iterator.NextItem())
            {
                Console.WriteLine(item.Name);
            }
            Console.ReadKey();
        }