DesignPattern - Iterator Pattern

1. Definition:

Let us first look at the strict definition of Decorator Pattern,

Iterator Pattern provides a way to access the elements of an aggregate object sequentially without knowing its underlying representation. (Wiki_Link_For_More_Info)


Iterator Patterns has multiple advantages.

  1. It allows us to iterate different absurb data structure uniformly, making the iteration trivial. That is the traversal operation is defined for an aggregate object without chaning its interface.
  2. It enables the traversal of data structure without knowing the detailed representation of that data structure. That is encapsulation benefit.
  3. Since it is a kind of lazy evaluation, i.e. we ask one and it gives us one at a time, therefore our collection can also be infinite, and at the same time we can pause at any where we want.

2. General UML of Iterator Pattern

Then, let us look the General UML of Iterator Pattern.

Smiley face
UML for iterator pattern

We have two interfaces, Iterable and iterator. Once a concreate class implements Iterable interface, it must override the iterator() method. It create a concreate Iterator by passing itself to the constructor of concreate Iterator. This means that given a concrete iterable ,it produces a concreate iterator. The concreate iterator may also have the private access to its related iterable reference so that it can access the field or methods defined in iterable. Iterator Pattern allows designer to decouple the enumerate functionality with others and unify by the interface.

3. Example

Suppose We have a collection of labels (of Type String) on one Node and we want to enumerate them. The codes are as follows:

Iterable Interface:

public interface Iterable<T> {

    Iterator<T>  getIterator();
}

Iterator Interface:

public interface Iterator<T> {
    boolean hasNext();
    T next();
}

Concreate Class which implements the iterable interface.

public class NodeLabels implements  Iterable {
    private String[] labels;

    public NodeLabels(String[] labels) {
        this.labels = labels;
    }

    public String[] getLabels() {
        return labels;
    }

    public void setLabels(String[] labels) {
        this.labels = labels;
    }

    @Override
    public Iterator<String> getIterator() {
        return new NodeLabelsIterator(this);
    }
}

Concreate Class which implements the iterator interface.

public class NodeLabelsIterator implements  Iterator {

    private NodeLabels nodeLabels;

    private int pointer;

    public NodeLabelsIterator(NodeLabels nodeLabels) {
        this.nodeLabels = nodeLabels;
        this.pointer = -1;
    }

    @Override
    public boolean hasNext() {
        return this.pointer < nodeLabels.getLabels().length-1;
    }

    @Override
    public String next() {
        return this.nodeLabels.getLabels()[++pointer];
    }
}

Test Function(Client)

public class Main {

    public static void main(String[] args) {
        String[] labels = new String[] {"Person","Movie","CAT","DOG"};
        Iterable<String> iterable = new NodeLabels(labels);
        Iterator<String> iterator = iterable.getIterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

OutPut:

Person
Movie
CAT
DOG
Process finished with exit code 0

Explain:

  1. In the interface, we usually use generic T to represent any possible Object Type.In the concreate class implementation, we should specify the types.
  2. In the concreate iterator class, we should have a pointer pointing to where we have traversed.
  3. Concreate iterable is responsible for create its concreate iterator by passing itself to the iterator constructor. Client has no aware of that.
  4. Client can only have the access to the iterable interface and iterator interface.

UML diagram

Smiley face

Author: Liang Tan
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source Liang Tan !
  TOC