Iteratorパターン

Java言語で学ぶデザインパターン入門」で勉強中。まずは最初にでてくるIteratorパターンだ。
Iteratorはよく使う。最近だと拡張forループを使うから、直接コードを書くことはほとんどないけど。
でもIteratorを作ることはあまりなかった。
サンプルのコードは、すべて合わせても100行くらいだが、いろいろ考えなくてはならないことが多い。
なんでここはAbstractメソッドなんだろうとか、なぜAggregateが必要なんだろうとか。
ちゃんと理解できるのはまだまだ先になりそう。


さてはて、Iteratorでよくわからないことがある。
なぜIteratorには、現在のindexを取ってくる方法がないのだろう。
iterator.getCurrentIndex()とか、あったら便利なのになぁと思う。
多分僕の考えが浅いから、深い思想を読み取れていないんだろうなぁ。よりシンプルにするためなのかな。


例えば、ユーザのリストがあって、ユーザIDの桁数チェックをしてから、実際の処理を行うを考える。
ユーザIDが桁数オーバなら、エラーログを出力する。
こんな要件があったら、エラーログにはエラーとなったユーザは何番目か出したくなる。
でも下みたいにIterator(拡張forループ)を使っているとできない。
結局カウンタ用の変数を用意しなくてはならない。なんか、かっこわるい。
これなら普通のforループでもいいような気がする。

import java.util.ArrayList;
import java.util.List;

public class IteratorSample {

  public static void main(String[] args) {
    List<User> userList = new ArrayList<User>(){{
      add(new User("001"));
      add(new User("002"));
      add(new User("00003"));
      add(new User("004"));
      }};
    
    int i = 0; 
    for(User user : userList){
      // 桁数チェック
      int idSize = user.getId().getBytes().length;
      if(idSize == 3){
        // OKなら本当は処理を行う
        System.out.println( i + "OK UserId : " + user.getId());
      }else{
        // エラーになったデータが何個目だったか出したい
        System.out.println("NGは" + i + "個目 NG UserId : " + user.getId());
      }
      i++;
    }
  }
}

class User{
  String id;
  public User(String id){
    this.id = id;
  }
  public String getId() {
    return id;
  }
}

# Listの初期化は「Javaの匿名クラスを使ってかっこよくオブジェクトを初期化するテクニック - 矢野勉のはてな日記」を参考にさせていただいた。


あー、書いてたら、なんとなく分かってきた(ような気がする)。
普通のforループで処理するより、Iteratorを直接使うより、拡張forループでカウンタ用の変数を定義するのがいちばん良さそう。
拡張forループならuserListがArrayListでもVectorでも配列でもコードの修正がいらない。
あー、でもArrayListVectorもListを実装しているから、普通のforループでもあまり変わらないか。
これではIteratorと普通のforループではなく、拡張forループと普通のforループの比較だな。


どっちにしてもindexは取れない。


でもさらに調べて、JavaDocを読んでいると、ListにはlistIterator()というメソッドがあって、ListIteratorが返ってくる。
そしてListIteratorには int nextIndex() と int previousIndex() メソッドがある!

Iterator<User> it = userList.listIterator();

ってやってみた。でも nextIndex() がない!
当たり前だ。Iteratorインターフェースにはそんなメソッドはない。
というわけで、こんな感じになった。

ListIterator<User> it = userList.listIterator();
while(it.hasNext()){
  System.out.println(it.nextIndex() + " " + it.next().getId());
}

うーん、これ使うことあるのかな。たぶん無いと思うなぁ。
継承を使って、Iteratorを拡張しているのは分かるけど、なんだかあまりよい設計に思えない。
# Java標準APIに文句をつけれるほどのスキルはないのだが・・・。


支離滅裂なエントリになったなぁ。

参考文献

増補改訂版Java言語で学ぶデザインパターン入門
結城 浩
価格:¥ 3,990