「Rubyによるデザインパターン」の読書メモです。
時々、個人の見解入りです。
集約オブジェクトがもとにある内部表現を公開せずに、その要素に順にアクセスする方法を提供する
外部イテレータ
class ArrayIterator
def initialize(array)
@array = array
@index = 0
end
def has_next?
@index < @array.length
end
def item
@array[@index]
end
def next_item
value = @array[@index]
@index += 1
value
end
end
array = ['red','green', 'blue']
i = ArrayIterator.new(array)
while i.has_next?
p "item: #{i.next_item}"
end
内部イテレータ
def for_each_element(array)
i = 0
while i < array.length
yield(array[i])
i += 1
end
end
a = [10, 20, 30]
for_each_element(a) { |element| p "The element is #{element}" }
外部イテレータと内部イテレータ
外部イテレータはクライアントが繰り返しを制御します。
内部イテレータは始めから終わりまで実行されます。
Enumerable モジュールを使う
class Account
attr_accessor :name, :balance
def initialize(name, balance)
@name = name
@balance = balance
end
def <=>(other)
balance <=> other.balance
end
end
class Portfolio
include Enumerable
def initialize
@accounts = []
end
def each(&block)
@accounts.each(&block)
end
def add_account(account)
@accounts << account
end
end
a1 = Account.new('account1', 200)
a2 = Account.new('account2', 400)
a3 = Account.new('account3', 600)
portfolio = Portfolio.new
arr = [a1, a2, a3]
arr.each do |a|
portfolio.add_account(a)
end
p portfolio.any? {|account| account.balance > 500}
p portfolio.all? {|account| account.balance > 500}
コードブロックで判定条件を渡せます。
注意点
test.rb
array = ['red', 'green', 'blue', 'purple']
array.each do |color|
p color
if color == 'green'
array.delete(color)
end
end
出力結果
$ ruby test.rb
"red"
"green"
"purple"
blue がスキップされてしまいました
test.rb
def change_resistant_for_each_element(array)
copy = Array.new(array)
i = 0
while i < copy.length
yield(copy[i])
i += 1
end
end
array = ['red', 'green', 'blue', 'purple']
change_resistant_for_each_element(array){|color|
p color
if color == 'green'
array.delete(color)
end
}
配列を削除しても、全部捜査されました。
出力結果
$ ruby test.rb
"red"
"green"
"blue"
"purple"