Паттерн Iterator
Часть раздела Объектно-ориентированное программирование путешествия по C на Coddy. Урок 56 из 61.
Паттерн Iterator предоставляет способ последовательно получать элементы из collection, не раскрывая её внутреннюю структуру. Вместо того чтобы предоставлять пользователям direct доступ к array, вы даёте им объект, который умеет проходить по data, получая по одному element за раз.
Итератору обычно нужны две части информации: ссылка на collection и текущая position. В C мы создаём структуру для хранения этого состояния:
typedef struct {
int* data; // указатель на массив
int size; // общее количество элементов
int current; // текущая позиция
} IntIterator;Итератор предоставляет две ключевые functions. has_next() проверяет, есть ли ещё more elements для чтения, а next() возвращает current element и advances position:
int has_next(IntIterator* it) {
return it->current < it->size;
}
int next(IntIterator* it) {
return it->data[it->current++];
}Использование iterator выглядит аккуратно и скрывает детали array:
IntIterator it = create_iterator(numbers, 5);
while (has_next(&it)) {
printf("%d\n", next(&it));
}Вызывающей стороне никогда не нужно знать, что numbers — это массив, или как работает indexing. Эта абстракция позволяет легко изменить базовую структуру данных в дальнейшем, например с массива на связный список, не изменяя код, который использует iterator.
Задание
ЛегкоДавайте создадим итератор NumberList: чистую абстракцию, которая позволяет перебирать collection целых чисел, не раскрывая лежащую в основе структуру array.
Вы организуете код в трёх файлах:
iterator.h: Define структуруIntIterator, которая хранит указатель на array целых чисел, общий размер collection и текущую position. Declare три functions:create_iterator(принимает указатель на array и размер, возвращает initialized iterator),has_next(проверяет, остались ли ещё elements) иnext(возвращает current element и advances position). Не забудьте include guards!iterator.c: Implement ваши functions итератора. Functioncreate_iteratorдолжна возвращатьIntIteratorпо значению с current position, установленной в 0. Functionhas_nextвозвращает 1, если осталось больше elements для чтения, и 0 otherwise. Functionnextвозвращает element в current position, а затем increments position.main.c: Прочитайте number elements, затем прочитайте each integer value в array. Create iterator для этого array, затем используйте цикл while сhas_nextиnext, чтобы перебрать и вывести each element в отдельной строке.
Ваша программа получит:
- Количество elements в array
- Каждое integer value в отдельной строке
Используйте паттерн iterator, чтобы вывести все elements: никакого direct indexing array в вашем цикле обхода!
Пример output, когда inputs — это 4, затем 10, 20, 30, 40:
10
20
30
40Пример output, когда inputs — это 3, затем -5, 0, 100:
-5
0
100Пример output, когда inputs — это 1, затем 42:
42Итератор скрывает способ хранения data. Ваш основной цикл просто спрашивает «есть ли ещё элементы?» и «дай мне следующий», ничего не зная об array indices или размещении в памяти.
Попробуйте сами
#include <stdio.h>
#include "iterator.h"
int main() {
int n;
scanf("%d", &n);
int arr[n];
// TODO: Прочитайте n целочисленных значений в массив
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
// TODO: Создайте итератор для массива
// TODO: Используйте цикл while с has_next и next для обхода
// и выведите каждый элемент на своей строке
// НЕ используйте прямую индексацию массива в цикле обхода!
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы модульного программирования
Заголовочные файлыСтражи включенияИсходные файлыСтатические функцииПовторение: Модульный калькулятор4Инкапсуляция
Концепция непрозрачных указателейОпределение непрозрачных структурГеттеры и сеттерыВалидация в сеттерахИтоги: Секретный ящик2Объекты и методы
Структуры как объектыУказатель 'Self'Константная корректностьУказатель против значенияВспомогательные методыИтоги: Point Manager5Проект: Простой банковский счет
Настройка проектаРеализация счета3Жизненный цикл объекта
Паттерн «Конструктор»Паттерн «Деструктор»Инициализация в стекеГлубокое копированиеПовторение: String Wrapper6Наследование через композицию
Встраивание структурПравило первого элементаДоступ к элементам родителяUpcastingПовторение: Иерархия фигур9Проект: Рисование фигур
Обзор проектаРеализация кругаРеализация прямоугольникаПолиморфное использованиеКонтейнер фигурПотренируйтесь самостоятельно: Онлайн-компилятор C