Открыть меню

Разбор Паттерна «Итератор»

Тип: поведенческий.

Назначение:

Позволяет последовательно перебирать элементы составного объекта (коллекции, источника данных) без раскрытия его внутреннего представления.

Схема(refactoring.guru):

На мой взгляд, паттерн очень хорошо описан в «Банде Четырех». Лишь подмечу некоторые моменты своими словами для лучшего понимания.

СТРУКТУРА КОДА ПРИ ИСПОЛЬЗОВАНИИ ШАБЛОНА

  1. Есть некий составной объект. В простейшем случае можно представить себе реальную коллекцию(имею ввиду класс) вроде eloquent из laravel, где объекты уже сформированы и лежат в памяти, но это не обязательно так. Я встречал и другие примеры, по сути здесь может быть любой источник данных — внешнее api, redis, база данных. В таком случае коллекция объектов ещё не собрана, но концептуально можно себе представить базу данных как коллекцию записей. Этакая, виртуальная коллекция.
  2. Клиентский код, которому нужно последовательно(важно!) получать элементы из этой коллекции и при этом не зависеть от её реализации. Использует метод коллекции createIterator(), полученный итератор и его элементы.
  3. Есть класс-итератор, который берет на себя обязанность по перебору коллекции из п.1(то есть знает алгоритм перебора) и во вне доступен только по интерфейсу «iterator».
  4. Есть интерфейс «IterableCollection», который нужен для того, чтобы клиентский код мог получить доступ к итератору и зависеть только от интерфейса.
  5. Коллекция реализует интерфейс «IterableCollection», у неё появляется метод для доступа к итератору.

В каких условиях выгодно применять

  1. Обязательное, но недостаточное условие применения паттерна — вызывающему коду необходимо последовательно перебирать объекты коллекции. По моему опыту, операции, где критически важен именно последовательный перебор, достаточно редкие. Признак такой ситуации — использование генераторов в PHP. И именно в таких условиях можно задуматься про iterator. Иначе проще получить из коллекции выборку нужных элементов и работать с ней. Например, при помощи отдельных методов коллекции, или же, чтоб не размывать ответственность класса, вынести выборку в отдельный класс. На мой взгляд, так логичнее и нагляднее, вместо вызова метода $collection->createRedElementsIterator():iterable, запросить у коллекции метод $collection->getRedElements():array.
  2. Не хотим раскрывать алгоритм перебора элементов коллекции. Например, там сложная логика.
  3. Не хотим размывать ответственность коллекции всевозможными выборками(особенно, если их много).
  4. Клиентский код вынужден работать с несколькими коллекциями и в нём есть общая механика работы с элементами каждой коллекций. В этом случае итератор можно использовать для создания единого интерфейса обхода элементов.

 

Из книги:

5. поддержка нескольких активных обходов одного и того же агрегирован-
ного объекта

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

Паттерн интересный, но конкретно в PHP, я нахожу не так много условий для его использования.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

© 2022 Продвижение сайтов в Санкт-Петербурге · Копирование материалов сайта без разрешения запрещено