IO Language Event Dispatcher
Callbacks are a great way of keeping different Objects loosely coupled, without having to hard code direct references or calls between collaborators. Languages that support blocks/closures offer an elegant and flexible alternative to approaches of the Java
interface
style.
EventDispatcher := Object clone do( listeners := Map clone subscribe := method(event, callback, listeners hasKey(event) ifFalse(listeners atPut(event, List clone)) listeners at(event) append(callback) ) notify := method(event, args, if(listeners hasKey(event), listeners at(event) foreach(callback, callback call(args)) ) ) )
The above
EventDispatcher
Object comes with two methods,
subscribe
and
notify
.
The most interesting bit is how
subscribe
maps registered callbacks to their respective events. Upon notification (the
notify
method), every callback registered with the given event will execute.
factory := EventDispatcher clone do( produceWidget := method(color, "I am creating a #{color} widget" interpolate println notify("new_widget", color) ) )
The code above signifies that every time the Factory produces a Widget, it will notify any listener interested in monitoring the production of new widgets. Interestingly, the factory knows nothing about listeners. IO scores some extra, not visible in this example, points by supporting Multiple Inheritance (sounds scary, but it's closer to Ruby's Mixins, rather than C++). Any ol' Object can have the
EventDispatcher
's
functionality available by adding
EventDispatcher
to it's list of
Protos
.
Following is an example Listener that registers its intentions of being notified about the creation of new Widgets with the Factory.
widgetCounter := Object clone do( counts := Map clone factory subscribe("new_widget", block(color, counts hasKey(color) ifFalse(counts atPut(color, 0)) counts atPut (color, counts at(color) nextInSequence) "#{counts at (color)} #{color} widget(s) created since I started listening" interpolate println ) ) )
Now, if the factory produces a few Widgets...
factory produceWidget("blue") factory produceWidget("green") factory produceWidget("blue") factory produceWidget("blue") factory produceWidget("red")
widgetCounter
keeps track of the them, in respects to their colors...
~/Desktop $ io EventDispatcher.io I am creating a blue widget 1 blue widget(s) created since I started listening I am creating a green widget 1 green widget(s) created since I started listening I am creating a blue widget 2 blue widget(s) created since I started listening I am creating a blue widget 3 blue widget(s) created since I started listening I am creating a red widget 1 red widget(s) created since I started listening
The example was inspired and is a port of the recipe described in chapter 7.11 Coupling Systems Loosely with Callbacks found in O'Reilly's Ruby Cookbook by Lucas Carlson and Leonard Richardson