[Java] Iterator pattern

2 minute read

The role of Iterator

The role of scanning elements in order

``’’ java package iterator;

public interface Iterator { public abstract boolean hasNext(); public abstract Object next(); }


The role of ###ConcreteIterator (concrete iterator)
A role that implements the interface defined by the Iterator role

``'' java
package iterator;

public class BookShelfIterator implements Iterator {
private BookShelf bookShelf;
private int index;

public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0;
}

public boolean hasNext() {
return index <bookShelf.getLength();
}

public Object next() {
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
}

Aggregate role

An interface that creates the Iterator role.

``’’ java package iterator;

public interface Aggregate { public abstract Iterator iterator(); }


### Concrete Aggregate role
Role that implements the interface defined by Aggregate role

``'' java
package iterator;

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

public class BookShelf implements Aggregate {
private List<Book> books;

public BookShelf() {
this.books = new ArrayList<>();
}

public Book getBookAt(int index) {
return books.get(index);
}

public void appendBook(Book book) {
books.add(book);
}

public int getLength() {
return books.size();
}

public Iterator iterator() {
return new BookShelfIterator(this);
}
}

Class that represents a bookshelf (aggregate)

``’’ java package iterator;

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

public class BookShelf implements Aggregate { private List books;

public BookShelf() { this.books = new ArrayList<>(); }

public Book getBookAt(int index) { return books.get(index); }

public void appendBook(Book book) { books.add(book); }

public int getLength() { return books.size(); }

public Iterator iterator() { return new BookShelfIterator(this); }

}


### Class that represents a book
``'' java
package iterator;

public class Book {
private String name;

public Book(String name) {
this.name = name;
}

public String getName() {
return this.name;
}

}

Caller

``’’ java package iterator;

public class Main {

public static void main(String[] args) { BookShelf bookShelf = new BookShelf(); bookShelf.appendBook(new Book(“Effective Java”)); bookShelf.appendBook(new Book(“CODE COMPLETE”)); bookShelf.appendBook(new Book(“readable code”)); bookShelf.appendBook(new Book(“Legacy code improvement”)); Iterator it = bookShelf.iterator(); while (it.hasNext()) { Book book = (Book)it.next(); System.out.println(book.getName()); } } }



Why is it necessary to create the Iterator role outside the aggregate?
The main reason is that by using Iterator you can count up separately from the implementation.

``'' java
while (it.hasNext()) {
Book book = (Book)it.next();
System.out.println(book.getName());
}

Only the Iterator methods called hasNext method and next method are used in the above code. The method used in the BookShelf implementation has not been called. So this loop is independent of the BookShelf implementation.

Consider a case where BookShelf quits managing books with List and changed to use arrays. No matter how you change BookShelf, BookShelf has iterator, If you return a correct iterator (hasNext and next will return an instance of a class that implements it correctly) then the above loop does not need to be modified at all.

Program using abstract classes and interfaces

People who are not familiar with how to use abstract classes and interfaces tend to suddenly program on the role of ConcreteAggregate or ConcreteIterator instead of the Aggregate interface or Iterator interface.

If you use only concrete classes, the coupling between the classes will become strong and it will be difficult to reuse them as parts.

Abstract classes and interfaces are introduced to weaken the binding and make it easier to reuse as class parts.

Tags:

Updated: