Паттерн «Итератор»
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy. Урок 76 из 87.
Iterator Pattern — это поведенческий шаблон проектирования, который предоставляет способ последовательно получать доступ к элементам коллекции, не раскрывая её внутреннюю структуру. Независимо от того, работаете ли вы с array, связным списком или деревом, iterator предоставляет единообразный способ обхода элементов.
Шаблон отделяет логику обхода от самой коллекции. Он включает два основных компонента: интерфейс Iterator, определяющий методы для обхода элементов, и Iterable (или Aggregate), который создаёт итераторы для своей коллекции:
interface Iterator<T> {
boolean hasNext();
T next();
}
interface Container<T> {
Iterator<T> createIterator();
}
class BookShelf implements Container<String> {
private String[] books;
private int count = 0;
public BookShelf(int size) {
books = new String[size];
}
public void addBook(String book) {
books[count++] = book;
}
public Iterator<String> createIterator() {
return new BookIterator();
}
private class BookIterator implements Iterator<String> {
private int index = 0;
public boolean hasNext() {
return index < count;
}
public String next() {
return books[index++];
}
}
}iterator поддерживает its собственное состояние обхода, позволяя нескольким iterator независимо обходить одну и ту же коллекцию. Клиенты используют iterator, не зная, как коллекция хранит свои данные:
BookShelf shelf = new BookShelf(3);
shelf.addBook("Design Patterns");
shelf.addBook("Clean Code");
Iterator<String> iterator = shelf.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}Встроенные в Java интерфейсы Iterable и Iterator следуют этому точному шаблону, поэтому вы можете использовать расширенные циклы for с любым классом, который реализует Iterable. Паттерн Iterator необходим, когда вам нужно предоставить несколько способов обхода или скрыть сложные внутренние структуры от клиентского кода.
Задание
ЛегкоСоздадим систему плейлистов с использованием паттерна Iterator! Ты создашь музыкальный плейлист, который хранит песни и предоставляет пользовательский итератор для последовательного перебора, не раскрывая способ внутреннего хранения песен. Это идеальный вариант использования паттерна Iterator, позволяющий пользователям перемещаться по твоей коллекции через чистый и единообразный интерфейс.
Ты организуешь код в четырех файлах:
Iterator.java: Define свой generic интерфейсIterator<T>с двумя методами:hasNext(), который возвращает boolean, указывающий, существуют ли еще элементы, иnext(), который возвращает следующий элемент типа T.Playlist.java: Create aggregate class, которая holds песни. ТвойPlaylistдолжен хранить песни в массиве String с фиксированной capacity (переданной в constructor) и отслеживать, сколько песен было added. Добавь методaddSong(String song)для добавления песен в плейлист.Твоему Playlist нужен метод
createIterator(), который возвращаетIterator<String>. Implement это, создав private inner class с именемPlaylistIterator, который implements твой интерфейс Iterator. Этот inner iterator хранит собственную позицию index и выполняет перебор массива песен, возвращая каждую песню по порядку.Song.java: Create простой классSong, который оборачивает название песни. У него должны быть constructor, принимающий название (String), методgetTitle()и методtoString(), который возвращаетPlaying: [title].Main.java: Объедини свою систему итераторов! Ты получишь один input: список названий песен, разделенных запятыми (например:Bohemian Rhapsody,Stairway to Heaven,Hotel California).Create Playlist с capacity для 10 песен. Разбери input и добавь каждое название песни в плейлист. Затем получи iterator из плейлиста и используй его для перебора всех песен, выводя каждую из них, обернутую в объект Song (который будет отображаться как
Playing: [title]).После перебора всех песен выведи
Playlist complete!в новой строке.
Ты получишь один input: строку с названиями песен, разделенными запятыми.
Например, для input Yesterday,Imagine,Let It Be результатом будет:
Playing: Yesterday
Playing: Imagine
Playing: Let It Be
Playlist complete!Обрати внимание, как твой класс Main использует методы hasNext() и next() итератора для перебора плейлиста, ничего не зная о внутренней структуре массива. Итератор инкапсулирует всю логику перебора, сохраняя внутреннее представление коллекции скрытым от клиентского кода!
Попробуйте сами
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
// TODO: Создайте Playlist вместимостью на 10 песен
// TODO: Разберите ввод (через запятую) и добавьте название каждой песни в playlist
// TODO: Получите итератор из playlist с помощью createIterator()
// TODO: Используйте итератор для обхода всех песен
// Для каждой песни оберните её в объект Song и выведите её
// TODO: Print "Playlist complete!" after iterating through all songs
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»Потренируйтесь самостоятельно: Онлайн-компилятор Java