The Iterator pattern. Java implementation with support for polymorphic container and polymorphic iterator
Contents
- 1. Block diagram of the Iterator pattern with binding to Java code.
- 2. Program implementation
- 3. Adding a new iterator. Sequence of steps
- 4. Adding a new container. Sequence of steps
- Related topics
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.
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.
- Create a class that implements the IIterator<T> interface.
- Declare the internal data in the class that are specific to the given iterator.
- Declare the implementation of the methods declared in the IIterator<T> interface.
- 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.
- Create a class that implements the IAggregate<T> interface.
- Declare the internal data of the container class. It can be an array, a list, a tree, a lot of the like.
- Declare methods that provide the main functionality of the container (add a new element, remove an element, etc.).
- Implement the methods declared in the IAggregate<T> interface.
- 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
- General information. Methods of implementation. Structural scheme. Example on C++
- The Iterator pattern. Features of implementation in C++ for polymorphic container and polymorphic iterator
- External and internal iterator. Implementation in C++
- The Iterator pattern. Implementation in C#
⇑