Iterator is a behavioral design pattern that allows sequential traversal through a complex data structure without exposing its internal details.
Thanks to the Iterator, clients can go over elements of different collections in a similar fashion using a single iterator interface.
Complexity:
Popularity:
Usage examples: The pattern is very common in Ruby code. Many frameworks and libraries use it to provide a standard way for traversing their collections.
Identification: Iterator is easy to recognize by the navigation methods (such as next
, previous
and others). Client code that uses iterators might not have direct access to the collection being traversed.
Conceptual Example
This example illustrates the structure of the Iterator design pattern. It focuses on answering these questions:
What classes does it consist of?
What roles do these classes play?
In what way the elements of the pattern are related?
main.rb: Conceptual example
class AlphabeticalOrderIterator
# In Ruby, the Enumerable mixin provides classes with several traversal and
# searching methods, and with the ability to sort. The class must provide a
# method each, which yields successive members of the collection.
include Enumerable
# This attribute indicates the traversal direction.
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
# The `iterator` method returns the iterator object itself, by default we
# return the iterator in ascending order.
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
# The client code may or may not know about the Concrete Iterator or Collection
# classes, depending on the level of indirection you want to keep in your
# program.
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: Execution result
Straight traversal:
First
Second
Third
Reverse traversal:
Third
Second
First
Iterator in Other Languages