「HeadFirstデザインパターン」と「Rubyによるデザインパターン」を読んで Iterator パターン


何番煎じか判りませんがお勉強メモを残します

HeadFirstデザインパターン」第2章
Rubyによるデザインパターン」第5章

Iterator パターン

「HeadFirstデザインパターン」でのJavaコードは(だいたい)こんな感じ

異なるCorrection 例えば

  • ArrayList
  • "配列"

に反復処理を行いたい場合、

ArrayList hogeArrayList = getHogeArrayList();

for (int i = 0, s = hogeArrayList.size(); i < s; i++) {
  Hoge hoge = (Hoge)hogeArrayList.get(i);
  // hoge への処理
}
Hoge[] hoges = getHogeArray();

for (int i = 0, l = hoges.length; i < l; i++) {
  Hoge hoge = hoges[i];
  // hoge への処理
}

何か微妙に違う・・!
反復処理を統一したい! collectionへの反復処理のカプセル化、それが

Iterator パターン

public interface Iterator {
  boolean hasNext();
  Object next();
}
public class HogeArrayListIterator implements Iterator {
  ArrayList<Hoge> hoges;
  int position = 0;

  public HogeArrayListIterator(ArrayList<Hoge> hoges) {
    this.hoges = hoges;
  }

  public Hoge next() {
    Hoge hoge = hoges.get(position);
    position++;
    return hoge;
  }

  public boolean hasNext() {
    if (position >= hoges.size()) {
      return false;
    }
    else {
      return true;
    }
  }
}

public class HogeArrayIterator implements Iterator {
  Hoge[] hoges;
  int position = 0;

  public HogeIterator(Hoge[] hoges) {
    this.hoges = hoges;
  }

  public Object next() {
    Hoge hoge = hoges[position];
    position++;
    return hoge;
  }

  public boolean nesNext() {
    if (position >= hoges.length) {
      return false;
    }
    else {
      return true;
    }
  }
}

つかいかた

ArrayList hogeArrayList = getHogeArrayList();
Hoge[]    hoges         = getHogeArray();

Iterator hogeArrayListIterator = new HogeArrayListIterator(hogeArrayList);
Iterator hogeArrayIterator     = new HogeArrayIterator(hoges);

while (hogeArrayListIterator.hasNext()) {
  Hoge hoge = (Hoge)hogeArrayListIterator.next()
  // hoge への処理
}

while (hogeArrayIterator.hasNext()) {
  Hoge hoge = (Hoge)hogeArrayIterator.next()
  // hoge への処理
}

つまり、どういうこと?

内部のcollectionを公開することなく、各アイテムに順次アクセスする方法を提供する

どうしてこんなことをするの?

「HeadFirstデザインパターン」では、ArrayListと配列で内部にcollectionを保持している2つのオブジェクトにおいて、
両方ともcollectionの持ち方を変えずに同じように扱いたい、というような例が挙げられていた

Rubyではどうなるんや?

class ArrayIterator
  def initialize(array)
    @array = array
    @index = 0
  end

  def has_next?
    @index < @array.length
  end

  def next_item
    value = @array[@index]
    @index += 1
    value
  end
end
hoges = [1, 2, 3, 4]

while hoges.has_next?
  p hoges.next_item
end
# =>
# 1
# 2
# 3
# 4

ていうか、rubyでは99%こんな事はしない

eachにブロックを渡すだけでいいのだから

hoges = [1, 2, 3, 4]

hoges.each do |hoge|
  p hoge
end
# =>
# 1
# 2
# 3
# 4