RubyIteratorPattern

2004-01-25 21:29:41 +0900 (1676d); rev 2

Ruby のイテレータを典型的なパターンに分類した。

繰り返し型

典型的な実例は Array#each、Hash#each、String#each_byte など。

最もありがちなイテレータの使いかた。 コレクションオブジェクトの各要素について順番にアクセスしていくときに使う。

また、Array#each_index や Integer#upto のように、 必ずしも「要素」でないオブジェクトに対して繰り返すこともある。

[実装例]

class SomeCollection1
  def each
    list = @list
    while list
      yield list.value
      list = list.next
    end
  end
end

class SomeCollection2
  def each(&block)
    @items.each(&block)
  end
end

仕事分割型

実例は IO#each、SMTP#sendmail など。

結果全部を一気に返すとでかすぎて危険な時に、 文字列 (など) を少しづつ渡すタイプ。 IO#each はどちらかというと行に分割するほうが主目的だが、 仕事を分割する目的にも (確実ではないが) 使えるので挙げてみた。 このタイプの特徴として、ブロックの引数を再現できないことが多い。

テンプレートメソッド型

典型的な例は Enumerable#map, select, inject など。

オブジェクトをパラメータ化したい時は引数を渡す。一方、コードをパラメー タ化したい時はイテレータを使ってブロックを渡す。テンプレートメソッドと かストラテジーと呼ばれるものがこの範疇である。このタイプはブロックの 返り値に意味があることが多い。

範囲型

典型的な例は IO#open、timeout など。

イテレータブロックの実行中だけ特定の環境を設定する。 必然的にこのタイプのイテレータは 「一回だけくりかえされるイテレータ」であることが多い。 開始と終了があるものにはほぼまちがいなくこのイテレータが適用できる。 特に終端が必須である場合は、ensure と組み合わせて 確実に終端が行われるイテレータを提供するとよい。

ちなみに C の malloc なんかは範囲型イテレータにできてもよさそうである。

[実装例]

class Resource
  def Resource.open(rc_name)
    begin
      rc = new(rc_name)
      yield rc
    ensure
      rc.free
    end
  end
end

コンテキスト型

典型的な例は module_eval と instance_eval。

インタプリタのコンテキストを設定するときに使う。 範囲型の特殊形。

登録型

典型的な例は signal、Gtk::Widget#signal_connect など。

いわゆるコールバックルーチンの登録をするときに使う。

[実装例]

class Listener
  def on_some_event(&block)
    @some_event_handler = block
  end
end

system revision 1.162