Patterns. The Iterator pattern. Java implementation




The Iterator pattern. Java implementation with support for polymorphic container and polymorphic iterator


Contents


Search other websites:

1. Block diagram of the Iterator pattern with binding to Java code.

The Figure 1 shows a diagram of the Iterator pattern with support for a polymorphic container and a polymorphic iterator.

The schema of pattern Iterator with Java code support

Figure 1. The schema of pattern Iterator with Java code support

 

2. Program implementation
2.1. Classes required to demonstrate the pattern

To implement the Iterator pattern shown in Figure 1, you need the following minimum set of interfaces and classes:

  • generic interface IAggregate<T> – defines the basic methods needed to implement a container (aggregate). This interface will be implemented by classes of concrete containers (lists, arrays, etc.). Thanks to polymorphism, methods for the corresponding concrete container will be loaded for the client;
  • generic interface IIterator<T> – defines the list of methods needed to make the iterator work. Each specific iterator will be implemented in classes that implement this interface;
  • one or more generic classes that implement the IAggregate<T> interface. These classes represent concrete containers. Each of the containers is a set of elements: an array, a list, and the like. More information about the kinds of container classes can be found here. In our case, we are demonstrating the development of one generic class named ConcreteAggregate<T>;
  • one or more generic classes that implement the IIterator<T> interface. These classes are iterators. As you know, there can be several iterators for a given container, for example, a forward iterator, a reverse iterator, and the like. You can read more about the classification of iterators here;
  • client class, will demonstrate how a specific iterator works for a specific container.

 

2.2. Interface IAggregate<T>. Common interface for all aggregates

The first interface in the program is declared, which is common to all classes of aggregates (containers or container classes). Aggregates can be lists, arrays, sets, and the like. In our case, the IAggregate<T> interface is declared. Here T is the name of some generic type.

The text of the TestIterator.java module, which demonstrates how the pattern works, is as follows.

// Pattern Iterator. Implementation in Java
// The interface of a container (aggregate)
interface IAggregate<T> {
  // Method that returns an iterator for the container
  IIterator<T> CreateIterator();

  // Method that returns the number of items in the container
  int Count();

  // A method that returns an element in a container at its index position
  T GetItem(int index);
}

public class TestIterator {
  public static void main(String[] args) {
  }
}

 

2.3. Interface IIterator<T>. Generalized iterator interface

At this stage, the IIterator<T> interface is added to the program. This interface must be implemented in concrete iterator classes.

After adding the interface, the abbreviated text of the program module is as follows.

// The Iterator pattern. Implementation in Java
// Container interface
interface IAggregate<T> {
  ...
}

// Iterator interface
interface IIterator<T> {
  // Rewind the cursor to the beginning of the set
  void First();

  // Rewind the cursor to the next item
  void Next();

  // Return the item to which the cursor points
  T CurrentItem();

  // Checking if the cursor is pointing to a position past
  // the last item in the set.
  boolean IsDone();
}

public class TestIterator {
  public static void main(String[] args) {
  }
}

 

2.4. The ConcreteIterator1<T> class of concrete iterator

Any concrete iterator class must implement the IIterator<T> interface. In our case, the concrete iterator class is named ConcreteIterator1<T>. The following elements are declared in a concrete iterator class:

  • internal field aggregate – a reference to a specific container;
  • internal field current – cursor that points to some item in the container;
  • a constructor that receives a reference to the IAggregate<T> interface;
  • method First() – moves the cursor to the first item of the container (the element at position 0);
  • method Next() – implements moving the cursor one position forward;
  • method IsDone () – determines whether the current cursor points to the position that is set after the last element;
  • method CurrentItem() – Returns the item pointed to by current.

After adding the ConcreteIterator1<T> class, the abbreviated code is as follows:

// The Iterator pattern. Implementation in Java
// The container interface
interface IAggregate<T> {
  ...
}

// The interface of an iterator
interface IIterator<T> {
  ...
}

// The class of concrete iterator
class ConcreteIterator1<T> implements IIterator<T> {

  // Internal class fields
  private final IAggregate<T> aggregate; // reference to the container
  private int current; // the current cursor position

  // Constructor for iterator
  public ConcreteIterator1(IAggregate<T> agg) {
    aggregate = agg;
    current = 0;
  }

  // Implementing methods declared in the IIterator<T> interface
  // Move cursor to first item
  public void First() {
    current = 0;
  }

  // Move cursor to the next item
  public void Next() {
    current++;
  }

  // Check whether the end of a set of elements
  public boolean IsDone() {
    return current >= aggregate.Count();
  }

  // Return the current item
  public T CurrentItem() {
    if (!IsDone())
      return aggregate.GetItem(current);
    else
      throw new ArrayIndexOutOfBoundsException("Error.");
  }
}

public class TestIterator {
  public static void main(String[] args) {
  }
}

 

2.5. The class of concrete aggregate

All container classes must implement the IAggregate<T> interface. In our case, the container class ConcreteAggregate1<T> is created, which is a dynamic array of type ArrayList<T>. To use the ArrayList<T> you need to import the java.util.ArrayList module

import java.util.ArrayList;

The class contains the following components:

  • internal field array, which is a dynamic array of type ArrayList<T>;
  • a constructor that initializes the internal array with another array of type T[]. Other constructors can be implemented as desired;
  • the Append() method, which adds an item to the end of the container;
  • the Remove() method, which removes an element from the container by its index;
  • the Print() method, which prints the elements of the array;
  • method CreateIterator() – implements the method of the same name of the IAggregate<T> interface. The method returns a reference to the IIterator<T> interface;
  • the Count() method is an implementation of a method from the IAggregate<T> interface. The method returns the number of elements in the container;
  • the GetItem() method – returns the current item in the container with its position.

Considering the above, after adding the class, the abbreviated program listing is as follows.

import java.util.ArrayList;

// The Iterator pattern. Implementation in Java
// The interface of a container
interface IAggregate<T> {
  ...
}

// The interface of an iterator
interface IIterator<T> {
  ...
}

// The class of concrete iterator
class ConcreteIterator1<T> implements IIterator<T> {
  ...
}

// A class that implements a specific container.
// The container is an array of type ArrayList<T>
class ConcreteAggregate1<T> implements IAggregate<T> {
  // Internal class fields
  private ArrayList<T> array;

  // Constructor
  public ConcreteAggregate1(T[] _array) {
    array = new ArrayList<T>();
    for (int i=0; i<_array.length; i++)
      array.add(_array[i]);
  }

  // Container handling methods.
  // Add item to the end of container
  public void Append(T item) {
    array.add(item);
  }

  // Delete item from the container
  public void Remove(int index) {
    array.remove(index);
  }

  public void Print(String text) {
    System.out.println(text);
    for (int i=0; i<array.size(); i++)
      System.out.print(array.get(i) + " ");
    System.out.println();
  }

  // Methods of IAggregate<T> interface.
  // Return the iterator.
  public IIterator<T> CreateIterator() {
    return new ConcreteIterator1<T>(this);
  }

  // Return the length of the container
  public int Count() {
    return array.size();
  }

  // Return the current item
  public T GetItem(int index) {
    if ((index>=0)&&(index<array.size()))
      return array.get(index);
    else
      throw new ArrayIndexOutOfBoundsException("Error. Bad index.");
  }
}

// Client class
public class TestIterator {
  public static void main(String[] args) {
  }
}

 

2.6. Client class

The client code is shown in the main() function. The client code tests the operation of the Iterator pattern.

import java.util.ArrayList;

// The Iterator pattern. Implementation in Java
// The container interface
interface IAggregate<T> {
  ...
}

// The interface of an iterator
interface IIterator<T> {
  ...
}

// The class of concrete iterator
class ConcreteIterator1<T> implements IIterator<T> {
  ...
}

// Class that implements a concrete aggregate
class ConcreteAggregate1<T> implements IAggregate<T> {
  ...
}

public class TestIterator {
  public static void main(String[] args) {
    // Testing the Iterator pattern. Client code
    // 1. Declare the data array
    Double[] AD = { 1.1, 2.3, 8.5, -4.9 };

    // 2. Create container based on AD array
    ConcreteAggregate1<Double> ag1 = new ConcreteAggregate1<Double>(AD);
    ag1.Print("ag1");

    // 3. Create an iterator for ag1 container
    ConcreteIterator1<Double> it1 =
      (ConcreteIterator1<Double>) ag1.CreateIterator();

    // 4. Demonstrate the iterator
    System.out.println("-------------------");
    System.out.println("Access using iterator.");

    it1.First();
    while (!it1.IsDone()) {
      System.out.print(it1.CurrentItem()+" ");
      it1.Next();
    }
  }
}

The result of the program

ag1
1.1 2.3 8.5 -4.9
-------------------
Access using iterator.
1.1 2.3 8.5 -4.9

 

3. Adding a new iterator. Sequence of steps

To add a new specific iterator (such as a reverse iterator), follow these steps.

  1. Create a class that implements the IIterator<T> interface.
  2. Declare the internal data in the class that are specific to the given iterator.
  3. Declare the implementation of the methods declared in the IIterator<T> interface.
  4. Implement additional methods.

Sample code for the MyNewIterator<T> class could be, for example.

class MyNewIterator<T> implements IIterator<T>
{
  // 1. Internal data
  // ...

  // 2. Additional class methods
  // ...

  // 3. Methods that are declared in the IIterator<T> interface
  public void First() {
    ...
  }

  public void Next() {
    ...
  }

  public boolean IsDone() {
    ...
  }

  public T CurrentItem() {
    ...
  }

  // 4. Additional interface methods specific to this iterator
  // ...
}

 

4. Adding a new container. Sequence of steps

To add a new specific container, follow these steps.

  1. Create a class that implements the IAggregate<T> interface.
  2. Declare the internal data of the container class. It can be an array, a list, a tree, a lot of the like.
  3. Declare methods that provide the main functionality of the container (add a new element, remove an element, etc.).
  4. Implement the methods declared in the IAggregate<T> interface.
  5. Implement additional methods that provide container functionality.

For example, a class named MyNewAggregate<T> might have the following implementation.

class MyNewAggregate<T> implements IAggregate<T> {
  // 1. Internal class fields
  // ...

  // 2. Constructors and methods of handling the container
  // ...

  // 3. Methods of handling the container
  // ...

  // 4. Methods of IAggregate<T> interface
  // ...
  public IIterator<T> CreateIterator() {
    return new MyNewAggregate<T>(this);
  }

  public int Count() { ... }
  public T GetItem(int index) { ... }

  // 5. Additional specified methods
  // ...
}

 


Related topics