「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文では置き換えがたいケースがあるということで終わり。まあ、保守性があって安全に動けば、もう何でも良いや。