Iteratorパターンはfor文じゃダメなの?

「Iteratorパターンなんて使わなくても、for文を使えば良いんじゃないの?」

煽りではなく、不意にそう思ってしまった。でも、冷静に考えると、このふたつは等価であるとは限らない。そして、反復処理をそのコレクション型クラス自体に隠蔽することに、大きな意味があるな、と思い直した。危ない、危ない。

List list = new SomeArrayClass();
for (Iterator it = list.iterator(); it.hasNext();) {
    System.out.println(it.next());
}

これを for文 で扱おうとすると、SomeArrayClass が何者かを知らないといけないので、オブジェクト間の関係が密になってしまう。その正体が何なのかを意識しなくて良いのが、iterator の良いところ。極端な例ではあるけど、これなら将来的に SomeArrayClass の内部実装が変わることに耐えられる。

そこに気付いたところで、次なる疑問。じゃあ、拡張for文とは何が違うのか。

List<String> list = new SomeArrayClass<String>();
for (String str : list) {
    System.out.println(str);
}

こう書くと、上のIteratorパターンのサンプルとまったく同じ役割を果たしてくれる。何が違うんだろうと思って探索した結果、どうやら拡張for文は内部で iterator を使っている模様。ああ、そういうことでしたか。

こういうことをキチンと踏まえた上で、敢えてIteratorパターンを用いず、for文で反復制御を書くことに意味があるんだろうなあ。

Iteratorパターンとfor文が等価ではないのは、例えば以下の場合とかだろうか。

List list = new SomeArrayClass();
for (int i = list.size() - 1; i >= 0; i--) {
    // 配列を逆順で表示
    System.out.println(list.get(i));
}

このように、特別なケースとして細かい制御を加えようとするなら、どうしてもfor文を使わざるを得ない場面というのもありうる。仕方ない場合はね。

ただ、あるクラスの管理する情報にアクセスする場合、そのクラスのインタフェースに従うのが安全。ゼロから順にインデックスをなめることに意味がない場合、よくあるfor文は、論理エラーになってしまう。そういう場合、iterator は効力を発揮するはず。

  • 自身のコレクション要素をスペル順に走査するiterator
  • 日付をインクリメントするカレンダーのiterator
  • 行列を A11 から Aij まで順に走査するiterator

この例だと、ユーティリティ的な色合いが強い反復子のようだけど、こういう iterator が無いと意味をなさないクラスがある。集約オブジェクトに対するアクセス法としてIteratorパターンを考えれば、こういうのもアリかと。

そういうことで、Iteratorパターンはfor文では置き換えがたいケースがあるということで終わり。まあ、保守性があって安全に動けば、もう何でも良いや。

このエントリーのトラックバックURL
http://www.deftrash.com/admin/mt4/mt-tb.cgi/321