オブジェクト指向設計


Iteratorパターン - イテレータ・パターン

2008/08/19 23:33Update
TAGS: Iteratorパターン | 振る舞いパターン | GoF

IteratorパターンはGoFによる23種類のデザインパターンの振る舞いに関連するパターンの一つで、集合要素に順次アクセスする手法を提供します。

Iteratorパターン概要


IteratorパターンはListのような集合オブジェクトの各要素に順次アクセスする方法の実装を外部クラスに委譲するパターンです。

Iteratorパターンの使用シーン


◇集合する要素にアクセスする必要がある
◇要素に順次にアクセスする必要がある

問題


Iteratorパターンを使用する前に、なぜかIteratorパターンが必要なのか、Iteratorパターンは何の問題を解決するかを知っておかなければなりません。

次のサンプルから説明したいと思います。
例えば、BookListというBookクラスの集まるクラスがあるとします。
public class Book {
    ...
}

public class BookList {
    //Bookオブジェクトの集まり
    private MyList <Book>bookList = new MyList();

    //BookをBookListに追加
    public void addBook(Book book) {
        ...
    }

    //BookListからBookを削除
    public void deleteBook(Book book) {
        ...
    }

    //その他メソッド
    ...
}


BookListのbookListに含まれたBookオブジェクトに順次にアクセスする必要があった場合、どうやってそのアクセス方法を実装するの?

次のような方法があると考えられるかもしれません。

■方法1、集合クラス自身が順次にアクセスする方法を実装します。
public class BookList {
    private int index;
    ...
    //カレントBookを取得
    public Book getCurrentBook() {
        ...
        Book book = (Book)bookList.get(index);
        ...
        return book;
    }

    //次のBookが存在するかを判定します
    public boolean hasNext() {
        ...
    }
}



その利用方法は、
BookList bookList = ...;
...
while (bookList.hasNext()) {
    Book book = bookList.getCurrentBook();
    //Bookに対して何らかの処理(略)
    ...
}



■方法2、呼び元のクラスは順次にアクセスする方法を実装します。
public class BookList {
    ...
    public MyList getBookList() {
        ...
        return bookList;
    }
}



利用方法は
MyList <Book>bookDataList = bookList.getBookList();
...
for (int i=0; bookDataList != null && i<bookDataList.size(); i++) {
    Book book = bookDataList.get(i);
    //Bookを処理する
    ...
}


上の方法1及び方法2は集合要素bookListに含まれたBookに順次アクセスする手法を提供しています。

しかし、これは次のような問題が存在すると考えられます。

方法1の場合、BookListに複数の役割(責任)を担ってしまいます:Bookを追加・削除する役割を果たした一方、集合要素であるbookListに順次アクセスする機能も提供してしまいます。
Single Responsibility Principle (SRP) - OO設計のSRP単一責任原則


方法2の場合、BookListクラスは順次アクセスする機能を提供しませんが、BookListクラス自身の内部構造を外部にさらすことになってしまいします。上例の場合、外部はMyListに依存することなり、例えばMyListではなく、他のListやMapなどの実装に変更する場合、外部プログラムも変更せざるを得ません。

The Open-Closed Principle (OCP) - OO設計のOCP開放/閉鎖原則


Java Collection Framework(JCF)でIteratorパターンの実装


Javaでは、Java Collection FrameworkでIteratorパターンを次のように実装しています。

1、Iteratorインタフェース
public interface Iterator
{
    //次の要素は存在するかを判定します
    public abstract boolean hasNext();
    //次の要素を返します
    public abstract Object next();
    //現在の要素を削除します
    public abstract void remove();
}


2、Collectionインタフェース。iterator()を定義し、順次アクセスする機能をIteratorインタフェースを実装した外部クラスに委譲します。
public interface Collection
    extends Iterable
{
    ...
    //すべての要素に順次アクセスするためのインスタンスを取得します。
    public abstract Iterator iterator();
    ...
}



3、Collectionを実装した集合クラス及びIteratorの実装クラス
public abstract class AbstractList extends AbstractCollection implements List {
    ...
    //すべての要素に順次アクセスするためのインスタンスを取得します。
    public Iterator iterator() {
        //順次アクセスする機能をIteratorの実装クラスItrに委譲します。
        return new Itr();
    }

    //Iteratorの実装クラス
    private class Itr implements Iterator {
        ...
    }
    ...
}

//集合クラスの具体的な実装クラス
public class ArrayList extends AbstractList {
    ...
}


これはJCFによるIteratorパターン実装です。


Iteratorパターンのよくある実装例


wikimedia.orgでは、次のようなIteratorパターンの実装案を説明しています。



Iteratorインタフェース:順次にアクセスするためのhasNext()、next()メソッドを定義します。
ConcreteIteratorクラス:Iteratorインタフェースを実装したクラス。
Aggregateインタフェース:個々要素の集まりの抽象インタフェース。Iterator iterator()メソッドを定義しています。
ConcreteAggregateクラス:Aggregateの実装クラス。


本文の例をIteratorパターンで実装する場合、次のようになります。
public class public interface IBookList {
    public BookListIterator iterator();
}
BookListImpl implements IBookList {
    public BookListIterator iterator() {
        return new BookListIteratorImpl(this);
    }
}
public interface BookListIterator {
    public boolean hasNext();
    public Book next();
}
public class BookListIteratorImpl implements BookListIterator {
    ...(具体的な実装を省きます)
}



そして、順次にアクセスする方法は、
IBookList list = ...;
BookListIterator it = list.iterator();
while(it.hasNext()){
    Book book = it.next();
    ...
}


Iteratorパターンのメリット


Iteratorパターンは「順次アクセスする方法」を外部クラスに委譲することで、次のようなメリットがあると考えられます。
◇ 個々の機能を適当なクラスに持たせることで、オブジェクト指向の単一責任原則に準拠します。
◇ 集合要素に複数の順次アクセス方法を提供することが可能になります。

有关作者
Syboos.jp編集長AJavaやオープンソース情報の執筆、Webサイトの開発や運営全般の業務に携わる。

Sponsored Link


Comments