Event listener
In
computer programming,
event listener is a
design pattern whose purpose is to distribute data to objects that register for it. The list of registered objects may change during the life of the program. When an event occurs the
channel broadcasts the event to all registered listeners.
Utilise when information needs to be distributed to a changing list of objects.
Procedure: The channel maintains a list of interested listeners, registering and deregistering them as requested. When information arrives, the channel
iterates through the list and calls a method in each object.
Also Known As:
Observer.
The
UML diagram below illustrates this structure:
Decide on a list of different kinds of events that are happening, and create a channel for each of them. When something subscribes to that channel, it gets notification of everything that comes in on it. In this case, there is one source and potentially many recipients. If the recipients also distribute information, there is no reason that they cannot also implement channels, though this might require the use of threads.
package EventChannel;
sub new {
my $type = shift;
my $me = { };
bless $me, $type;
}
sub addEventListener {
my $me = shift;
my $eventListener = shift; $eventListener->isa('EventListener') or die; $me->{$eventListener} = $eventListener;
return 1;
}
sub removeEventListener {
my $me = shift;
my $eventListener = shift; $eventListener->isa('EventListener') or die; delete $me->{$eventListener};
return 1;
}
sub broadcastEvent {
my $me = shift;
my $event = shift;
foreach my $i (values %$me) {
eval { $i->receiveEvent($event); };
warn $@ if($@);
}
}
package EventListener;
sub receiveEvent {
warn "EventListener::receiveEvent not overridden to do anything useful";
}
package IOServer; use EventChannel;
sub new {
my $type = shift;
my $filehandle = shift;
my $me = {fileHandle=>$filehandle}; }
sub start {
my $me = shift;
my $filehandle = $me->{'fileHandle'}; while(<$filehandle>) { $me->broadcastEvent($_);
}
}
# WonderWedge
package WonderWedge;
use EventListener;
@ISA = ('EventListener');
sub new {
my $type = shift;
my $me = { };
bless $me, $type;
}
sub receiveEvent {
my $me = shift;
print @_;
}
# main
package main;
use WonderWedge;
use IOServer;
my $stdinserver = new IOServer \*STDIN; $stdinserver->addEventListener (new WonderWedge); $stdinserver->start();
An event itself could, and often should, be represented as an object, too. In this example, we'll leave it as a scalar.
I have a Gnutella servant that allows user defined code to attach to it as daemons, in addition to a few built in ones. If I broadcast every message to every daemon object, I would be spending more time delivering messages than processing them, since most daemons aren't interested in most messages. Instead, interested daemons can register interest in connection notices, pong packs, search requests, and many other things that come in over the network. In fact, connections are presented as daemons themselves, and they listen for requests to relay or broadcast information from other daemons in the system. Since connections appear and vanish all of the time, it would be impossible to know in advance where to send packets. The solution is to have interested parties request them.
An advanced version of this is a ConstraintSystem.
* http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/131499 - in Python
* http://www.newsisfree.com/click/-4,16938591,2532,15945,mail/ - in Java (not working anymore)
* http://www.onjava.com/pub/a/onjava/2005/03/23/executors.html - Java 1.5 Flexible Event Delivery with Executors
The article is originally from the Perl Design Patterns Book