Паттерн Итератор предоставляет механизм последовательного перебора элементов коллекции без раскрытия ее внутреннего представления.
Кроме того, перебор элементов выполняется объектом итератора, а не самой коллекцией.
Это упрощает интерфейс, и реализацию коллекции, а также способствует более логичному распределению обязанностей. При использовании итераторов коллекция избавляется от одной обязанности поддержки операций перебора данных.
Итератор предоставляет общий интерфейс перебора элементов коллекции, что позволяет применять полиморфизм в коде, использующем элементы коллекции.
Представим, что у нас есть два класса, реализующие две разных коллекции, суть проблемы состоит в том, чтобы клиент не знал как эти коллекции реализованы, но имел возможность обходить последовательно все коллекции.
Давайте представим ситуацию нас наняли в качестве разработчика для написания программного обеспечения автомата, который будет выводить информацию клиенту о меню, цене и блюдах.
Как мы знаем утром мы не едим мясо, супы итд, потому что это эти блюда употребляем в обед, а завтракаем более легкой пищей. Соответственно для этой ситуации у нас должно быть 2 коллекции, завтрак и обед. Но проблема еще заключается в том, что в автомате до нас реализовали коллекцию завтраков, и менять мы ее не можем. Для решения этих целей и был придуман паттерн Итератор. Мы реализуем интерфейс.
IEnumerator
using System; using System.Collections; namespace Паттерн_Итератор { public class MenuItem { public string Name { get; } public string Description { get; } public bool Vegetarian { get; } public double Price { get; } public MenuItem(string name, string description, bool vegetarian, double price) { this.Name = name; this.Description = description; this.Vegetarian = vegetarian; this.Price = price; } } public class DinnerMenuIterator : IEnumerator { MenuItem []items; int position = 0; public DinnerMenuIterator(MenuItem[] items) { this.items = items; } public object Current { get { MenuItem menuItem = items[position]; position++; return menuItem; } } public bool MoveNext() { if (items == null || position >= items.Length) { return false; } else { return true; } } public void Reset() { if (position <= 0) { throw new Exception("Вы не можете удалить товар пока не вызовите MoveNext() "); } if (items[position - 1] != null) { for (int i = 0; i < items.Length - 1; i++) { items[i] = items[i + 1]; } items[items.Length - 1] = null; } } } public class BreakfastMenuIterator : IEnumerator { ArrayList items; int position = 0; public BreakfastMenuIterator(ArrayList items) { this.items = items; } public object Current { get { object menuItem = items[position]; position++; return menuItem; } } public bool MoveNext() { if (position >= items.Count || items[position] == null) { return false; } else { return true; } } public void Reset() { if (position <= 0) { throw new Exception("Вы не можете удалить товар пока не вызовите MoveNext() "); } if (items[position - 1] != null) { for (int i = 0; i < items.Count-1; i++) { items[i] = items[i + 1]; } items[items.Count - 1] = null; } } } public class DinnerMenu { MenuItem[] menuItems; public DinnerMenu() { menuItems = new MenuItem[] { new MenuItem("Манная каша", "Манная каша на миндальном молоке с ванилью", true, 120), new MenuItem("Чечевичный суп", "Чечевичный суп с томатами", true, 150), new MenuItem("Суп рассольник", "Постный рассольник", true, 180), new MenuItem("Фаршированные перцы", "Фаршированные перцы с грибами и кабачком", true, 230), new MenuItem("Овощное рагу", "Овощное рагу с мясом", false, 350), new MenuItem("Свинина", "Свинина под лимонной заправкой", false, 550), }; } //метод возвращает интерфейс IEnumerator, клиенту не нужно знать ничего о колекции. //клиент просто переберает элементы public IEnumerator CreateIterator() { return new DinnerMenuIterator(menuItems); } } public class BreakfastMenu { ArrayList menuItems; public BreakfastMenu() { menuItems = new ArrayList { new MenuItem("Блиный гурман", "Блинчики со взбитыми яцами и тостом", true, 130), new MenuItem("Обычны завтра из блинов", "Жареный блин с сосиской", true, 130), new MenuItem("Блины с черникой", "Блины со свежей черникой", true, 230), new MenuItem("Фруктовые блины", "Блины со свежей черникой и клубникой", true, 230) }; } //метод возвращает интерфейс IEnumerator, клиенту не нужно знать ничего о колекции. //клиент просто переберает элементы public IEnumerator CreateIterator() { return new BreakfastMenuIterator(menuItems); } } public class Automatic { BreakfastMenu breakfastMenu; DinnerMenu dinnerMenu; public Automatic(BreakfastMenu breakfastMenu, DinnerMenu dinnerMenu) { this.breakfastMenu = breakfastMenu; this.dinnerMenu = dinnerMenu; } public void PrintMenu() { IEnumerator breakfastIterator = breakfastMenu.CreateIterator(); IEnumerator dinnerIterator = dinnerMenu.CreateIterator(); Console.WriteLine("Меню\n----\nЗавтрак"); PrintMenu(breakfastIterator); Console.WriteLine("\nОбед"); PrintMenu(dinnerIterator); } void PrintMenu(IEnumerator iterator) { while (iterator.MoveNext()) { MenuItem menuItem = (MenuItem)iterator.Current; Console.WriteLine(menuItem.Name+", "); Console.WriteLine(menuItem.Price+" -- "); Console.WriteLine(menuItem.Description); } } } class Program { static void Main(string[] args) { BreakfastMenu breakfastMenu = new BreakfastMenu(); DinnerMenu dinnerfast = new DinnerMenu(); Automatic automatic = new Automatic(breakfastMenu, dinnerfast); automatic.PrintMenu(); Console.ReadKey(); } } }
Меню
----
Завтрак
Блиный гурман,
130 --
Блинчики со взбитыми яцами и тостом
Обычны завтра из блинов,
130 --
Жареный блин с сосиской
Блины с черникой,
230 --
Блины со свежей черникой
Фруктовые блины,
230 --
Блины со свежей черникой и клубникой
Обед
Манная каша,
120 --
Манная каша на миндальном молоке с ванилью
Чечевичный суп,
150 --
Чечевичный суп с томатами
Суп рассольник,
180 --
Постный рассольник
Фаршированные перцы,
230 --
Фаршированные перцы с грибами и кабачком
Овощное рагу,
350 --
Овощное рагу с мясом
Свинина,
550 --
Свинина под лимонной заправкой