ActionScript.org Flash, Flex and ActionScript Resources - http://www.actionscript.org/resources
Centralized Event Management in Actionscript 2.0
http://www.actionscript.org/resources/articles/610/1/Centralized-Event-Management-in-Actionscript-20/Page1.html
Jason Cook
Jason Cook is a developer and designer with an eleven-year history of successful products in the entertainment industry. Jason is also a prolific DJ and producer producing original Drum & Bass , Techno and Breakbeat and performing around the globe, from the West Coast of the United States to the far Eastern edge of Europe. Jason lives in Hollywood, California, USA with his wife who keeps asking him to teach her Flash. 
By Jason Cook
Published on May 21, 2007
 

Centralized Event Management in Actionscript 2.0

Assumed Knowledge: Event handling with EventDispatcher

Communicating between objects with Events rather than "direct addressing" is a powerful tool used in many object-oriented programming languages to decouple objects and classes from each other. Truly decoupled objects are highly liberated objects - they make no mention of each other in their source code, they do not import each others classes, they neither know nor care if each other exist. This is programming nirvana.

One barrier to achieving truly convenient, robust decoupling with EventDispatcher is that event listeners need to address a dispatcher directly with the addEventListener method to subscribe to the dispatcher's events. It may be inconvenient, convoluted or impossible for a listener object to subscribe to the dispatcher, especially when the dispatcher is not yet instantiated, resides in an unconnected SWF, or is otherwise difficult or impossible to address directly.

Another criticism of the way the EventDispatcher model is usually applied is that there tends to be a great deal of redundant code throughout an application. Every object, timeline or class that needs to dispatch events needs initialize EventDispatcher, define three EventDispatcher methods for type safety, and define a dispatching object.

An elegant, simple solution to both of these problems is to introduce a static intermediary class that handles all event routing. In plain English, any object that wants to dispatch an event or listen to an event will do so through a universally accessible event utility class, instead of handling the work itself.

[as]
/**
 * Central event dispatching class [0.1.0]
 * All classes that need to dispatch or listen to events should use the services of this class.
 *
 * @class EventCenter
 * @author Jason Cook
 * @version 0.1.0
 *
 * @history 0.1.0 (2006.12.04) Created initial version of EventCenter.
 */
import mx.events.EventDispatcher;
class EventCenter {

 /**
  * Reference to this instance.
  */
 private static var _instance:EventCenter;

 /**
  * Event source object
  */
 private var _eventSource:Object;

 /**
  * Static accessor method.
  * @return A unique instance of this class.
  */
 public static function access():EventCenter {
  if (_instance == undefined )
     _instance = new EventCenter();
  return _instance;
 }

 /**
  * Private contructor initializes EventDispatcher. Access through EventCenter.access().
  */
 private function EventCenter() {
  _eventSource = {};
  EventDispatcher.initialize(_eventSource);
 }

 /**
  * Overridden EventDispatcher method addEventListener.
  * @param type  (String) The type of event to subscribe to.
  * @param listener (Object) The listener subscribing.
  * @return Void
  */
 public function addEventListener(type:String, listener:Object):Void {
  _eventSource.addEventListener(type, listener);
 }

 /**
  * Overridden EventDispatcher method removeEventListener.
  * @param type  (String) The type of event to unsubscribe from.
  * @param listener (Object) The listener unsubscribing.
  * @return Void
  */
 public function removeEventListener(type:String, listener:Object):Void {
  _eventSource.removeEventListener(type, listener);
 }

 /**
  * Overridden EventDispatcher method dispatchEvent.
  * @param event (Object) The event object to dispatch.
  * @return Void
  */
 private function dispatchEvent(event:Object):Void {
  _eventSource.dispatchEvent(event);
 }

 /**
  * Create an Event object and dispatch it. Call EventCenter.access().broadcast("myEvent", targetObject, {param0:value0, param1:value1, paramn:valuen}); to dispatch an event.
  * @param _type  (String) The type of event.
  * @param _target (Object) The object that dispatched this event. There is a known bug with this property. It always comes back as a slash (/). This may be a flaw in EventDispatcher. If you need to pass the event source include it as a _data parameter.
  * @param _data  (Object) A data vessel for any other data.
  * @return Void
  */
 public function broadcast(_type:String, _target:Object, _data:Object):Void {
  var event:Object = {type:_type, target:_target, data:_data};
  _eventSource.dispatchEvent(event);
 }
}
[/as]

Essentially, what this class does is it creates a wrapper around the EventDispatcher services. This class is accessed through static methods (like Math.random(), for example) so any object in your application has easy access to it without needing to find a path to a concrete object.

The EventDispatcher.initialize method requires a concrete event-sending object, which a purely static class does not provide. Since there needs to be an actual concrete object, the EventCenter.access() method calls its own constructor the first time it is used, and every time after that the EventCenter.access() method returns the unique instance of EventCenter. This is a terrific application of the Singleton design pattern.

The use of this class is elegant in its simplicity. This code demonstrates listening to a particular event.

[as]
import EventCenter;

// receiveObj can be any listener object you like and it can handle the event any way you like.

EventCenter.access().addEventListener("testEvent", receiveObj);

receiveObj.testEvent = onEventReceived;

function onEventReceived(event:Object):Void {
 var alertString:String = ("Event received - type: "+event.type+", target - "+event.target+", data:");
 for (var i:String in event.data) {
  alertString += " " + i + ": " + event.data[i] + ";";
 }
 trace(alertString);
}
[/as]

This demonstrates sending an event.

[as]
import EventCenter;

// sendObj can be any dispataching object you like.

EventCenter.access().broadcast("testEvent", sendObj, {sender:sendObj, message:"hello", someNumber:42});
[/as]

The first time you build an application with this type of event handling model you will be refreshed by the simplicity and effectiveness of its use. Your objects will remain truly decoupled and all your event dispatching functionality is neatly collected in one place.