2019-05-09
Rubyによるデザインパターン - iterator
[](http://www.amazon.co.jp/exec/obidos/ASIN/4894712857/hatena- blog-22/)
利用する場面
あるオブジェクトが複数の子要素をもっており、それを連続して走査したい場合。
(この親要素を集約オブジェクトと呼ぶ。)
方法
- 外部イテレータ
- 集約オブジェクトとは別に iterate するためのオブジェクトをつくる。
- 外部イテレータに#next みたいなメッセージを送ることで、外部から iterate を操作する。
- 内部イテレータ
- 集約オブジェクトと別に iterate するためのオブジェクトをつくらない。
- ブロックを受け取って、後は内部でガーッと iterate する。その過程でブロックを yield する。
その他
- イテレータを使うらしい。
- iterator が存在する。
- ほとんどは内部イテレータとして使うことができる。
File#readline
で 1 つすすみ、File#eof?
で位置を確認する。
サンプル
外部イテレータ
class Parent
attr_reader :children
def initialize(*children)
@children = children
end
end
class Child
def initialize(name)
@name = name
end
end
class ChildrenIterator
def initialize(parent)
@parent = parent
@index = 0
end
def has_next?
@index < @parent.children.length - 1
end
def child
@parent.children[@index]
end
def next
raise "no younger child" unless has_next?
@index += 1
end
end
namihei = Parent.new(Child.new(:sazae), Child.new(:katsuo), Child.new(:wakame))
i = ChildrenIterator.new(namihei)
while true do
p i.child
i.has_next? ? i.next : break
end
# => #<Child:0x007ff53c195aa8 @name=:sazae>, #<Child:0x007fa40307d290 @name=:katsuo>, #<Child:0x007fa40307d268 @name=:wakame>
内部イテレータ ①:地に直接 iterate するためのメソッドを書く。
class Parent
attr_reader :children
def initialize(*children)
@children = children
end
end
class Child
def initialize(name)
@name = name
end
end
def iterate_children(parent)
i = 0
while i < parent.children.size
yield(parent.children[i])
i += 1
end
end
namihei = Parent.new(Child.new(:sazae), Child.new(:katsuo), Child.new(:wakame))
iterate_children(namihei) { |child| p child }
# => #<Child:0x007f9a971976f0 @name=:sazae>, #<Child:0x007f9a97197650 @name=:katsuo>, #<Child:0x007f9a97197628 @name=:wakame>
内部イテレータ ②:集約オブジェクトに iterate するためのメソッドを書く。
class Parent
attr_reader :children
def initialize(*children)
@children = children
end
def iterate_children
i = 0
while i < children.size
yield(children[i])
i += 1
end
end
end
class Child
def initialize(name)
@name = name
end
end
namihei = Parent.new(Child.new(:sazae), Child.new(:katsuo), Child.new(:wakame))
namihei.iterate_children { |child| p child }
# => #<Child:0x007f9a971976f0 @name=:sazae>, #<Child:0x007f9a97197650 @name=:katsuo>, #<Child:0x007f9a97197628 @name=:wakame>