第1章 Iterator - 増補改訂版Java言語で学ぶデザインパターン入門

というわけで、デザインパターンの復習。第1章のIteratorパターンから。

  • Iteratorパターンを使うメリットは、集合体の実装と、集合体から個体を取り出す動作を分離できること。

集合体がどんなふうに実装されていても、集合体用のIteratorが正しいかぎりは、使う側が個体を取り出す動作を変えなくてよい、と書いてあります。便利。

  • 集合体の実装と数え上げの実装は、密接に関連している。集合体の実装に変更が加われば、数え上げの実装も変更する必要がある。

数え上げを実装したクラスのnext()では、次の要素を取得して、インデックスを1進めます。next()は、内部で、集合体の実装クラスに記述された「指定したインデックスの要素を返す」メソッドを使っています。集合体の実装変更によって、「指定したインデックスの要素を返す」メソッドがシグネチャごと変わってしまうと、next()も変更することになりますよ、という話。

Iteratorパターンの実装は、java.util.Iteratorインタフェースに見ることができる。

複数のIteratorを併用する方法

サンプルプログラムのIterator実装は、集合体に対して、順方向に一度だけ走査します。では、異なる走査の仕方をするIterator後から併用したくなったら、どのように実現するとよいのか?

集合体の実装では、すでにAggregateインタフェースのiterator()をオーバライドしている。このiterator()は、順方向に走査するIteratorを作るためのものだ。となると、逆方向に走査するIteratorを作るメソッドを別に定義する必要がある。

ここで、Iterator (Java Platform SE 6)ListIterator (Java Platform SE 6)を見てみる。

逆方向に走査するメソッドは、Iteratorインタフェースでなく、Iteratorを拡張したListIteratorインタフェースにある。この方法を参考にすると、こうなる。まず、元のIteratorを拡張したListIteratorを作る。次に、ListIteratorに逆走査メソッドを追加する。最後に、逆走査メソッドを使いたいクラスで、IteratorでなくListIteratorを実装する。

元のIteratorインタフェースを肥大させないように気をつけよう(昔よくやってた…)。インタフェースに後からメソッドを追加するのは、じごくの入り口。

ジェネリックスを使う

練習問題の解答のサンプルコードでは、AllayListが生のままで使われている。

    // (付属CDルート)/src/Iterator/A1/BookShelf.java から引用
    
    private ArrayList books;   
    public BookShelf(int initialsize) {         
        this.books = new ArrayList(initialsize);   
    }                                           
    public Book getBookAt(int index) {
        return (Book)books.get(index);          
    }

取り出し時にキャストしなくてよいように、ジェネリックスを使ってみる。

	// 変更後
	private ArrayList<Book> books;
	
	public BookShelf(int initialize) {
		this.books = new ArrayList<Book>(initialize);
	}
	
	public Book getBookAt(int index) {
		return books.get(index);
	}

for文でhasNextを使う

サンプルコードでは、hasNextの条件付き繰返しをwhile文で書いている。

	// (付属CDルート)/src/Iterator/Sample/BookShelf.java から引用
	Iterator it = bookShelf.iterator();
	while (it.hasNext()) {
		Book book = (Book)it.next();
		System.out.println(book.getName());
		}

変数のスコープを最小にしよう、という理念にしたがって、この部分をfor文にしてみる。

	// 変更後
	for(Iterator it = bookShelf.iterator();it.hasNext();) {
		Book book = (Book)it.next();
		System.out.println(book.getName());			
	}

なぜこうするのかについて、コードで説明しているページを見つけたので、メモ。

http://www.sgnet.co.jp/java/chapter0101.html

第1章は、ここまで。