The role of scanning elements in order
package iterator;
public interface Iterator {
public abstract boolean hasNext();
public abstract Object next();
}
A role that implements the interface defined by the Iterator role
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;
}
}
An interface that creates the role of Iterator.
package iterator;
public interface Aggregate {
public abstract Iterator iterator();
}
A role that implements the interface defined by the Aggregate role
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);
}
}
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);
}
}
package iterator;
public class Book {
private String name;
public Book(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
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 do we need to create an Iterator role outside the aggregate? The main reason is that by using Iterator, it is possible to count separately from the implementation.
while (it.hasNext()) {
Book book = (Book)it.next();
System.out.println(book.getName());
}
Only the Iterator methods, hasNext and next, are used in the above code. The methods used in the BookShelf implementation have not been called. So this loop doesn't depend on the BookShelf implementation.
Consider the case where BookShelf quits managing books with List and changes to use arrays. No matter how you change the BookShelf, the BookShelf has an iterator and If you return the correct iterator (if you return an instance of the class where the hasNext and next methods are implemented correctly), you don't need to change the above loop at all.
People who don't understand how to use abstract classes and interfaces tend to program on the role of Concrete Aggregate or Concrete Iterator instead of the Aggregate interface or Iterator interface (I am now ...).
If only specific classes are used, the bonds between the classes will be 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 a class part.
Recommended Posts