Iterator pattern in Java and Python Development 26.02.2017

Behavioral Design Patterns provide solution for the better interaction between objects and how to provide lose coupling and flexibility to extend easily. Following design patterns come under this category.

Iterator pattern presents a way to access the elements of an object without exposing the underlying presentation.

Iterator pattern is one of the behavioral pattern and it’s used to provide a standard way to traverse through a group of Objects.

Iterator pattern is widely used in java collection framework where Iterator interface provides methods for traversing through a collection.

The logic for iteration is embedded in the collection itself and it helps client program to iterate over them easily. Iterator pattern is not only about traversing through a collection; we can provide different kind of iterators based on our requirements. Iterator pattern hides the actual implementation of traversal through the collection and client programs just use iterator methods. An Iterator object contains public methods to allow a client object to navigate through the list of objects within the container.

dp_iterator.gif
  • Iterator defines an interface for accessing and traversing elements.
  • ConcreteIterator implements the Iterator interface and keeps track of the current position in the traversal of the aggregate.
  • Aggregate defines an interface for creating an Iterator object.
  • ConcreteAggregate implements the Iterator interface to return an instance of the proper ConcreteIterator.

When to use the Iterator design pattern

  • To access an aggregate object’s contents without exposing its internal representation.
  • To support multiple traversals of aggregate objects.
  • To provide a uniform interface for traversing different aggregate structures (that is, to support polymorphic iteration).
  • Iterator pattern is useful when you want to provide a standard way to iterate over a collection and hide the implementation logic from client program.

Java

Let's look at an example of this. We have an Item class, which represents an item on a menu. An item has a name and a price.

File Item.java.

public class Item {
    String name;
    float price;

    public Item(String name, float price) {
        this.name = name;
        this.price = price;
    }

    public String toString() {
        return name + ": $" + price;
    }
}

Here is the Menu class. It has a list of menu items of type Item. Items can be added via the addItem() method. The iterator() method returns an iterator of menu items. The MenuIterator class is an inner class of Menu that implements the Iterator interface for Item objects. It contains basic implementations of the hasNext(), next(), and remove() methods.

File Menu.java.

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Menu {
    List menuItems;

    public Menu() {
        menuItems = new ArrayList<Item>();
    }

    public void addItem(Item item) {
        menuItems.add(item);
    }

    public Iterator<Item> iterator() {
        return new MenuIterator();
    }

    class MenuIterator implements Iterator<Item> {
        int currentIndex = 0;

        @Override
        public boolean hasNext() {
            if (currentIndex >= menuItems.size()) {
                return false;
            } else {
                return true;
            }
        }

        @Override
        public Item next() {
            return menuItems.get(currentIndex++);
        }

        @Override
        public void remove() {
            menuItems.remove(--currentIndex);
        }
    }
}

The Demo class demonstrates the iterator pattern. It creates three items and adds them to the menu object. Next, it gets an Item iterator from the menu object and iterates over the items in the menu. After this, it calls remove() to remove the last item obtained by the iterator. Following this, it gets a new iterator object from the menu and once again iterates over the menu items.

File Demo.java.

import java.util.Iterator;

public class Demo {
    public static void main(String[] args) {
        Item i1 = new Item("spaghetti", 7.50f);
        Item i2 = new Item("hamburger", 6.00f);
        Item i3 = new Item("chicken sandwich", 6.50f);

        Menu menu = new Menu();
        menu.addItem(i1);
        menu.addItem(i2);
        menu.addItem(i3);

        System.out.println("Displaying Menu:");
        Iterator<Item> iterator = menu.iterator();
        while (iterator.hasNext()) {
            Item item = iterator.next();
            System.out.println(item);
        }

        System.out.println("\nRemoving last item returned");
        iterator.remove();

        System.out.println("\nDisplaying Menu:");
        iterator = menu.iterator();
        while (iterator.hasNext()) {
            Item item = iterator.next();
            System.out.println(item);
        }
    }
}

Python 3

import abc

class Item:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    def __str__(self):
        return "{}: $ {}".format(self.name, self.price)

class MenuIterator:
    def __init__(self, items):
        self.indx = 0
        self.items = items

    def has_next(self):
        return False if self.indx >= len(self.items) else True

    def next(self):
        item = self.items[self.indx]
        self.indx += 1
        return item

    def remove(self):
        return self.items.pop()

class Menu:
    def __init__(self):
        self.items = []

    def add(self, item):
        self.items.append(item)

    def iterator(self):
        return MenuIterator(self.items)

if __name__ == '__main__':
    i1 = Item("spaghetti", 7.50)
    i2 = Item("hamburger", 6.00)
    i3 = Item("chicken sandwich", 6.50)

    menu = Menu()
    menu.add(i1)
    menu.add(i2)
    menu.add(i3)

    print("Displaying Menu:")
    iterator = menu.iterator()

    while iterator.has_next():
        item = iterator.next()
        print(item)

    print("Removing last item returned")
    iterator.remove()

    print("Displaying Menu:")
    iterator = menu.iterator()
    while iterator.has_next():
        item = iterator.next()
        print(item)