Весенняя РАСПРОДАЖА
Итератор

Итератор на Ruby

Итератор — это поведенческий паттерн, позволяющий последовательно обходить сложную коллекцию, без раскрытия деталей её реализации.

Благодаря Итератору, клиент может обходить разные коллекции одним и тем же способом, используя единый интерфейс итераторов.

Сложность:

Популярность:

Применимость: Паттерн можно часто встретить в Ruby-коде, особенно в программах, работающих с разными типами коллекций, и где требуется обход разных сущностей.

Признаки применения паттерна: Итератор легко определить по методам навигации (например, получения следующего/предыдущего элемента и т. д.). Код использующий итератор зачастую вообще не имеет ссылок на коллекцию, с которой работает итератор. Итератор либо принимает коллекцию в параметрах конструктора при создании, либо возвращается самой коллекцией.

Концептуальный пример

Этот пример показывает структуру паттерна Итератор, а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.

main.rb: Пример структуры паттерна

class AlphabeticalOrderIterator
  # Примесь Enumerable в Ruby предоставляет классы методами обхода, поиска и
  # сортировки значений. Класс, реализующий Enumerable должен определить метод
  # `each`, который возвращает (в yield) последовательно элементы коллекции.
  include Enumerable

  # Этот атрибут указывает направление обхода.
  # @return [Boolean]
  attr_accessor :reverse
  private :reverse

  # @return [Array]
  attr_accessor :collection
  private :collection

  # @param [Array] collection
  # @param [Boolean] reverse
  def initialize(collection, reverse: false)
    @collection = collection
    @reverse = reverse
  end

  def each(&block)
    return @collection.reverse.each(&block) if reverse

    @collection.each(&block)
  end
end

class WordsCollection
  # @return [Array]
  attr_accessor :collection
  private :collection

  def initialize(collection = [])
    @collection = collection
  end

  # Метод iterator возвращает объект итератора, по умолчанию мы возвращаем
  # итератор с сортировкой по возрастанию.
  #
  # @return [AlphabeticalOrderIterator]
  def iterator
    AlphabeticalOrderIterator.new(@collection)
  end

  # @return [AlphabeticalOrderIterator]
  def reverse_iterator
    AlphabeticalOrderIterator.new(@collection, reverse: true)
  end

  # @param [String] item
  def add_item(item)
    @collection << item
  end
end

# Клиентский код может знать или не знать о Конкретном Итераторе или классах
# Коллекций, в зависимости от уровня косвенности, который вы хотите сохранить в
# своей программе.
collection = WordsCollection.new
collection.add_item('First')
collection.add_item('Second')
collection.add_item('Third')

puts 'Straight traversal:'
collection.iterator.each { |item| puts item }
puts "\n"

puts 'Reverse traversal:'
collection.reverse_iterator.each { |item| puts item }

output.txt: Результат выполнения

Straight traversal:
First
Second
Third

Reverse traversal:
Third
Second
First

Итератор на других языках программирования

Итератор на C# Итератор на C++ Итератор на Go Итератор на Java Итератор на PHP Итератор на Python Итератор на Rust Итератор на Swift Итератор на TypeScript