LoginSignup
1

More than 3 years have passed since last update.

Iteratorパターン

Last updated at Posted at 2020-08-11

Iterator(反復子)の役

要素を順番にスキャンしていく役

package iterator;

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

ConcreteIterator(具体的な反復子)の役

Iterator役が定めたインターフェースを実装する役

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(集合体)の役

Iterator役を作り出すインターフェース。

package iterator;

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

ConcreteAggregate(具体的な集合体)の役

Aggregate役が定めたインターフェースを実装する役

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("リーダブルコード"));
        bookShelf.appendBook(new Book("レガシーコード改善"));
        Iterator it = bookShelf.iterator();
        while (it.hasNext()) {
            Book book = (Book)it.next();
            System.out.println(book.getName());
        }
    }
}

なぜわざわざ集合体の外にIterator役を作る必要があるのか?
大きな理由としてはIteratorを使うことで実装とは切り離して数え上げを行うことができるため。

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

上記コードで使われているのはhasNextメソッドとnextメソッドというIteratorのメソッドのみ。
BookShelfの実装で使われているメソッドは呼び出されていない。
つまりこのループはBookShelfの実装には依存していない。

BookShelfでListで本を管理することを辞め、配列を使うように変更した場合を考える。
BookShelfをどのように変更したとしても、BookShelfがiteratorを持っており、
正しいiteratorを返せば(hasNextとnextメソッドが正しく実装されているクラスのインスタンスを返してくれれば)、上記ループは全く変更する必要がない。

抽象クラスやインターフェースを使ってプログラミングする

抽象クラスやインターフェースの使い方がよく分からない人はAggregateインターフェースやIteratorインターフェースではなく、いきなりConcreteAggregate役やConcreteIterator役の上でプログラミングしてしまいがち(今の自分…)

具体的なクラスだけを使うと、クラス間の結合が強くなってしまい、部品として再利用することが難しくなる。

結合を弱め、クラス部品として再利用しやすくするために抽象クラスやインターフェースが導入される。

こちらを参考にさせていただきました。
増補改訂版Java言語で学ぶデザインパターン入門

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1