Паттерн «Итератор»
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy. Урок 76 из 87.
Паттерн «Итератор» — это поведенческий шаблон проектирования, который позволяет последовательно получать доступ к элементам коллекции, не раскрывая её внутреннюю структуру. Работаете ли вы с массивом, связным списком или деревом, итератор предоставляет единый способ обхода элементов.
Этот шаблон отделяет логику обхода от самой коллекции. Он включает два основных компонента: интерфейс 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++];
}
}
}Итератор поддерживает собственное состояние обхода, позволяя нескольким итераторам независимо обходить одну и ту же коллекцию. Клиенты используют итератор, не зная, как коллекция хранит свои данные:
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.java: Определи обобщённый интерфейсIterator<T>с двумя методами:hasNext(), который возвращает логическое значение и показывает, есть ли ещё элементы, иnext(), который возвращает следующий элемент типа T.Playlist.java: Создай класс-коллекцию, который хранит песни. ТвойPlaylistдолжен хранить песни в массиве String фиксированной ёмкости (переданной конструктору) и отслеживать, сколько песен было добавлено. Добавь методaddSong(String song)для добавления песен в плейлист.В твоём Playlist должен быть метод
createIterator(), который возвращаетIterator<String>. Реализуй его, создав приватный внутренний класс с именемPlaylistIterator, который реализует интерфейс Iterator. Этот внутренний итератор хранит собственную текущую позицию и перебирает массив песен, возвращая каждую песню по порядку.Song.java: Создай простой классSong, который хранит название песни. В нём должны быть конструктор, принимающий название (String), методgetTitle()и методtoString(), который возвращаетPlaying: [title].Main.java: Собери систему итератора воедино! На вход будет подан один набор данных: список названий песен, разделённых запятыми (например:Bohemian Rhapsody,Stairway to Heaven,Hotel California).Создай Playlist ёмкостью 10 песен. Разбери входные данные и добавь в плейлист каждое название песни. Затем получи итератор из плейлиста и используй его для перебора всех песен, выводя каждую из них в виде объекта Song (который будет отображаться как
Playing: [title]).После перебора всех песен выведи
Playlist complete!с новой строки.
На вход будет подана одна строка со списком названий песен, разделённых запятыми.
Например, если на вход подано 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: Разберите входную строку (значения разделены запятыми) и добавьте название каждой песни в плейлист
// TODO: Получите итератор плейлиста с помощью createIterator()
// TODO: Используйте итератор, чтобы перебрать все песни
// Для каждой песни создайте объект Song и выведите его
// TODO: Выведите "Playlist complete!" после перебора всех песен
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
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