【Java】Iteratorパターン 【デザインパターン】
目次
Iteratorパターン
Iteratorパターンとは
- ある集合体の要素を、順番にアクセスする方法を提供するパターンです
サンプルプログラム
- Iteratorパターンを使って、本棚の中に本を入れ、その本の名前を順番に表示するプログラムを実装します
- 各クラスとインターフェースの役割は以下のようになっています
名前 | 役割 |
---|---|
Aggregate | 集合体を表すインターフェース |
Iterator | 数え上げ、スキャンを行うインターフェース |
Book | 本を表すクラス |
BookShelf | 本棚を表すクラス(ConcreteAggregate) |
BookShelfIterator | 本棚をスキャンするクラス(ConcreteIterator) |
Aggregateインターフェース
- iteratorメソッドの宣言のみ行います
- このメソッドはIteratorを作成するためのものです
- 集合体を数え上げたい時に、このiteratorメソッドを使って、Iteratorインターフェース実装クラスのインスタンスを生成します
- iteratorメソッドはBookShelfクラスで実装します
public interface Aggregate { public abstract Iterator iterator(); }
Iteratorインターフェース
- 次の要素が存在するかどうかを調べるhasNextメソッドと、次の要素を得るnextメソッドを宣言します
- nextメソッドの戻り値はObject 型です。集合体の要素を一個返すようにBookShelfIteratorクラスで実装します
public interface Iterator { public abstract boolean hasNext(); public abstract Object next(); }
Bookクラス
public class Book { private String name; public Book(String name) { this.name = name; } public String getName() { return name; } }
BookShelfクラス
- 本棚を表現するクラスです
- このクラスを集合体として扱う為に、Aggregateインターフェースを実装し、iteratorメソッドの実体を記述します
return new BookShelfIterator(this);
でBookShelfIteratorクラスのインスタンスを生成して返します
- Bookクラスのbooksという配列をフィールドに持ちます
- 配列の大きさをインスタンス生成時に指定します
public class BookShelf implements Aggregate { private Book[] books; private int last = 0; public BookShelf(int maxsize) { this.books = new Book[maxsize]; } public Book getBookAt(int index) { return books[index]; } public void appendBook(Book book) { this.books[last] = book; last++; } public int getLength() { return last; } public Iterator iterator() { return new BookShelfIterator(this); } }
BookShelfIteratorクラス
- 本棚のスキャンを行います
- Iteratorとして扱う為、Iteratorインターフェースを実装します
- nextメソッドでindexを++することで、ループ変数を次に進めます
- BookShelfクラスのインスタンスをbookShelfフィールドに保存します
- 注目している本をindexフィールドに保存します
public class BookShelfIterator implements Iterator { private BookShelf bookShelf; private int index; public BookShelfIterator(BookShelf bookShelf) { this.bookShelf = bookShelf; this.index = 0; } public boolean hasNext() { if (index < bookShelf.getLength()) { return true; } else { return false; } } public Object next() { Book book = bookShelf.getBookAt(index); index++; return book; } }
Mainクラスで本棚のスキャンを実行します
Iterator it = bookShelf.iterator();
では、BookShelfIterator型の変数ではなく、Iterator型の変数に代入しています
import java.util.*; public class Main { public static void main(String[] args) { BookShelf bookShelf = new BookShelf(4); //4冊入る本棚を作成 bookShelf.appendBook(new Book("Java言語で学ぶデザインパターン入門")); bookShelf.appendBook(new Book("独習Java")); bookShelf.appendBook(new Book("徹底攻略Java SE 11 Silver問題集")); bookShelf.appendBook(new Book("Spring解体新書")); Iterator it = bookShelf.iterator(); //本棚をスキャンするためのIteratorインスタンス生成 while (it.hasNext()) { //次の本があるか確認 Book book = (Book)it.next(); //本を一つずつ調査 System.out.println(book.getName()); } } }
Iteratorパターンを使うメリット
- Main関数のwhileで呼び出すのは、hasNext、nextのIteratorメソッドのみで、BookShelfメソッドは呼び出していません
- つまり、whileループはBookShelfの実装に依存しない、ことになります
- よって、BookShelfの実装を変更しても、iteratorメソッドを持っていて、hasNextとnextを実装しているインスタンスを返してくれたら(正しくIteratorを返しているので)、Mainメソッドのwhileループは変更しなくても動作する!のです
- こうすることで、結合度を下げ、クラスを部品として再利用しやすくすることができます
今日のポイント
- Iteratorパターンは、ある集合体の要素を、順番にアクセスする方法を提供するパターンです
- 動作を実行するMain関数のwhileループで呼び出すのは、Iteratorメソッドのみで、BookShelfメソッドは呼び出していません
- これにより、結合度を下げ、クラスを部品として再利用しやすくすることができます
本日もお疲れ様です😊