• Register

There are 23 classic design patterns, which are described in the original book, Design Patterns: Elements of Reusable Object-Oriented Software. These patterns provide solutions to particular problems, often repeated in the software development.

In this article, I am going to describe what the Iterator Pattern is; and how and when it should be applied.

Iterator Pattern: Basic Idea

In object-oriented programming, the iterator pattern is a design pattern in which an iterator is used to traverse a container and access the container's elements. The iterator pattern decouples algorithms from containers; in some cases, algorithms are necessarily container-specific and thus cannot be decoupled.  — Wikipedia

Provide a way to access the elements of an aggregate object sequentially
without exposing its underlying representation. - Design Patterns: Elements of Reusable Object-Oriented Software

The main feature of this pattern is that it lets you traverse elements of a collection without exposing its underlying representation (array, map, tree, etc.). Therefore, these are two problems that this pattern resolves:

  • Decoupling of algorithms and collections.
  1. Allows us to change the internal implementation of a collection with no change in the algorithm's implementation.
  2. Allows us to add new algorithms which work all existing collection types.
To sum up, the iterator pattern hides the internal implementation of a collection from the client. The UML diagram of this pattern is the following one

 

The Iterator class is an interface witch defines the different operations to navegate through to the collection (next or hasNext) while that Aggregate class will create the Iterator. Finally, the system will use the ConcreteAggregate and ConcreteIterator.

Iterator Pattern: When To Use

  1. Your collection has a complex data structure under the hood, but you want to hide its complexity from clients.
  2. You need to reduce duplication of traversal code across your app.
  3. You want your code to be able to traverse different data structures.

Iterator Pattern: Advantages

The Iterator Pattern has several advantages, summarised in the following points:

  • The code is easier to use, understand and test since the iterator uses the Single Responsibility and Open/Closed SOLID principles.
  • The Single Responsibility Principle allows us to clean up the client and collections of the traversal algorithms.
  • The Open/Closed Principle allows implementation of new types of collections and iterators without breaking anything.
  • Parallel iteration over the same collection because each iterator object contains its own iteration state.
  • Clean code because the client/context does not use a complex interface and the system is more flexible and reusable.

Iterator pattern - Example 1: Words Collection

I will now show you how you can implement this pattern using JavaScript/TypeScript. In our case, I have made up a problem in which there is a class named WordsCollection which defines a word's list (items) and its set of methods to get and add (getItems and addItem). This class is used by the client using control structures, such as for or forEach. The following UML diagram shows the scenario that I have just described.

The WordsCollection code associate is the following ones:
export class WordsCollection {
  private items: string[] = [];

  public getItems(): string[] {
    return this.items;
  }

  public addItem(item: string): void {
    this.items.push(item);
  }
}

The client code associate is the following ones:

import { WordsCollection } from './words-collection';

const collection = new WordsCollection();
collection.addItem('First');
collection.addItem('Second');
collection.addItem('Third');

const items = collection.getItems();
const elements = items.length;

console.log('Straight traversal:');
for (let i = 0; i <= elements; i++) {
  console.log(items[i]);
}

console.log('');
console.log('Reverse traversal:');
for (let i = elements; i > 0; i--) {
  console.log(items[i]);
}
The main problem in this solution is that the code is coupled. Meaning that, the client needs to known how is the internal structure of the collection to implement the two traversed methods (Straight and Reverse). Imagine that you need change the data structure from Array to Map then the code associated to the client is breaking due to the coupling. Other interesting use case of Iterator pattern is when you need a new way to iterate the collection, for example, AlphabeticalOrdered.
The solution is to use an iterator pattern and the new UML diagram using this pattern is shown below:

Therefore, the solution consists of an interface class (Iterator) which defines the method to traverse the collection:

  1. current(): T.
  2. key(): number.
  3. hasMoreElements(): boolean.
  4. rewind: void.
export interface Iterator<T> {
  // Return the current element.
  current(): T;

  // Return the current element and move forward to next element.
  next(): T;

  // Return the key of the current element.
  key(): number;

  // Checks if current position is valid.
  hasMoreElements(): boolean;

  // Rewind the Iterator to the first element.
  rewind(): void;
}

Read More...

More Posts

Benchmarking Array looping: for vs. for-in vs..forEach() vs. for-of Lelin - Apr 25
How to print an array in java. Hasnain_khan - Oct 9, 2020
SyntaxError: can't assign to literal, while running code to count number of vowels in string Tushar Shuvro - Jun 29, 2020
How to convert html field values to a json object Tushar Shuvro - Apr 25, 2020
C++ program accept five integer from user that will be stored in an array using pointer and print them in reverse order. Ahsan29 - May 7
What is the best way to read user inputs via scanner? Tushar Shuvro - Jul 1, 2020
Delete an element from an array C++. Lalit Kumar - Apr 26, 2020
Java Design patterns kesav.eee - May 13
Loop Quiz Questions and Answers You Need to Know Sana Sabir - Jan 27
Loops Quiz Questions and Answers ( Answered) Sana Sabir - Jan 27