7.11 使用回掉的松偶合系统
Coupling Systems Loosely with Callbacks
Here's a mixin module that gives each instance of a class its own hash of "listener" callback blocks. An outside object can listen for a particular event by calling subscribe with the name of the event and a code block. The dispatcher itself is responsible for calling notify with an appropriate event name at the appropriate time, and the outside object is responsible for passing in the name of the event it wants to "listen" for.
module EventDispatcher
def setup_
listeners
@event_dispatcher_listeners = {}
end
def subscribe(event, &callback)
(@event_dispatcher_listeners[event] ||= []) << callback
end
protected
def notify(event, *args)
if @event_dispatcher_listeners[event]
@event_dispatcher_listeners[event].each do |m|
m.call(*args) if m.respond_to? :call
end
end
return nil
end
end
Here's a Factory class that keeps a set of listeners. An outside object can choose to be notified every time a Factory object is created, or every time a Factory object produces a widget:
class Factory
include EventDispatcher
def initialize
setup_listeners
end
def produce_widget(color)
#Widget creation code goes here…
notify(:new_widget, color)
end
end
Here's a listener class that's interested in what happens with Factory objects:
class WidgetCounter
def initialize(factory)
@counts = Hash.new(0)
factory.subscribe(:new_widget) do |color|
@counts[color] += 1
puts "#{@counts[color]} #{color} widget(s) created since I started watching."
end
end
end
Finally, here's the listener in action:
f1 = Factory.new
WidgetCounter.new(f1)
f1.produce_widget("red")
# 1 red widget(s) created since I started watching.
f1.produce_widget("green")
# 1 green widget(s) created since I started watching.
f1.produce_widget("red")
# 2 red widget(s) created since I started watching.
# This won't produce any output, since our listener is listening to
# another Factory.
Factory.new.produce_widget("blue")