コールバックによるシステムの疎結合(Ruby)

Rubyクックブック ―エキスパートのための応用レシピ集』p.67-70 の読解

# encoding: Shift_JIS

module EventDispatcher
  def setup_listeners
    @edl = {}       #edlはevent_dispatcher_listeners
  end
  
  def subscribe(event, &callback)      #callbackはブロック(Proc)
    (@edl[event] ||= []) << callback   #ハッシュ@edlに{@edl[event]=>(@edl[event] <<  callback)}が追加される(@edl[evernt]はArray)
  end
  
  protected
  def notify(event, *args)
    if @edl[event]
      @edl[event].each do |m|                 #mはProcで、引数*argsをもつ
        m.call(*args) if m.respond_to? :call  #mがcallメソッドをもっていれば、ブロックを実行
      end
    end
    nil
  end
end

class Factory
  include EventDispatcher
  def initialize; setup_listeners; end
  
  def produce_widget(color)
    #ウィジェットを作成するコード
    notify(:new_widget, color)   #widgetを実行
  end
end

class WidgetCounter
  def initialize(f)                      #fはFactoryオブジェクト
    @cnts = Hash.new(0)
    f.subscribe(:new_widget) do |color|  #widgetの登録(do以下の:new_widgetブロックがsubscribeに引数として渡される)
      @cnts[color] += 1
      puts "#{@cnts[color]} 個の #{color} widget(s) が作成されています"
    end
  end
end


f1 = Factory.new
WidgetCounter.new(f1)     #"WidgetCounter" widgetの登録
f1.produce_widget("red")  #widgetの実行
f1.produce_widget("green")
f1.produce_widget("red")

結果

1 red widget(s) が作成されています
1 green widget(s) が作成されています
2 red widget(s) が作成されています