![]()
This is something simple enough that I hesitate to post it, but maybe someone else can benefit. Plus, I always try to have something new on Mondays. Anyway, this a technique I once used back in the dark ages of ActionScript development (meaning AS2). Last week, however, I suddenly had need of it again.
The AS3 event model is a pretty slick deal- much better than the six different ways we used to do it back in AS2. However, I ran into a spot last week in which it failed me. I had several different components in completely different parts of an application, and I wanted them all to listen to each other. That in itself is no problem. The problem was that I also wanted them to be completely unaware of each other, in hopes of keeping the code a bit more encapsulated. So how does one listen for an event that comes from a source whose very existence is unknown?
Option #1 was to make all my events bubble, and have each component add event listeners to some display list parent that all the components shared. This would ensure that everyone got their events, but it makes everyone dependent on the current setup. What if I wanted to move a component elsewhere and now it didn’t share that parent? Plus, it’s not a solution that is guaranteed to work in a different app. Plus, it involves children referencing their parent, which I am against on a fundamental, perhaps even a spiritual level. So, scratch Option #1.
Then I thought maybe each component should store a reference to all the other components. But once again, you can throw the whole “loosely-coupled” idea out the window. Something about this solution just didn’t feel right.
Option #3 was the old AS2 method of creating a central static Broadcaster class and telling everyone to listen to it. Now the only dependency each component had was to one static communication class. Everything else could change as long as they were listening to the Broadcaster. And so, as my great-grandmother has told me, sometimes the old ways are best.
There’s really not much to explain with this class. The only challenge was making a static class into an EventDispatcher, but that turned out to be pretty easy (thanks to G. Skinner, who originally gave me the idea for a static EventDispatcher). Behold:
/**
* A central event broadcaster
*
* @author Zack Jordan
* { P I X E L W E L D E R S . C O M }
*/
package com.pixelwelders.events
{
import flash.events.Event;
import flash.events.EventDispatcher;
public class Broadcaster
{
private static var eventDispatcher : EventDispatcher;
/**
* Broadcasts an event to all listeners
* To listen to any and all events, use Broadcaster.addEventListener()
*
* @param event The Event to broadcast
* @return nothing
*/
public static function broadcast( event:Event ): void
{
dispatchEvent( event );
}
// === S T A T I C E V E N T D I S P A T C H E R ===
public static function addEventListener( type:String, listener:Function, useCapture:Boolean=false,
priority:int=0, useWeakReference:Boolean=true ):void
{
if ( !eventDispatcher ) eventDispatcher = new EventDispatcher();
eventDispatcher.addEventListener( type, listener, useCapture, priority, useWeakReference );
}
public static function removeEventListener( type:String, listener:Function, useCapture:Boolean=false ):void
{
if ( eventDispatcher ) eventDispatcher.removeEventListener( type, listener, useCapture );
}
public static function dispatchEvent( p_event:Event ):void
{
if ( eventDispatcher ) eventDispatcher.dispatchEvent( p_event );
}
}
}
As you can see, this is just a static wrapper for an instance of EventDispatcher. I just route all the methods of the EventDispatcher to static methods, and voilá. As always, if you can think of a better way, just drop it in the comments.
Pretty neat, thanks! I had a similar problem and opted for solution #1, but when I had to move the components to different displaylists it got really messy…
Hi Zack,
Is it possible to use the following so as to remove the if statements?
private static var eventDispatcher:EventDispatcher = new EventDispatcher();
I’m pretty certain you can do that and i see no reasons not to…
Cheers
nice,
but any particular reason why you don’t just extend EventDispatcher and use singleton to access??
public class Broadcaster extends EventDispatcher
{
private static var _instance:Broadcaster = new Broadcaster();
function Broadcaster()
{
if ( _instance ) throw new Error( “Broadcaster and can only be accessed through Broadcaster.instance” );
}
public static function get instance():Broadcaster
{
return _instance;
}
}
Thanks for the clearly defined scenario Zack.
Surely an event broadcaster like this eliminates all the context of the Event - e.g. event.target becomes the Broadcaster instance rather than the “true” dispatcher?
How do you handle that?
This is great, the only thing I will be using this for is not just generic broadcasting of events, but making a specific broadcaster designed to connect a group of components.
For example, I have a toolbar in an application, and it needs to communicate directly to editable components. So I would create a dispatcher for just those elements.
I just wouldn’t like the idea of setting up a generic catch-all solution for _every_ component.
Great class, btw, thanks!
have you looked into a MVC?
http://puremvc.org/
This allows you to separate your UI, logic, and data.