Skip to content

Instantly share code, notes, and snippets.

@leegrey
Created September 15, 2012 07:48
Show Gist options
  • Save leegrey/3726860 to your computer and use it in GitHub Desktop.
Save leegrey/3726860 to your computer and use it in GitHub Desktop.
SignalHub.as is a Signal manager for AS3
/*
Commander:
Created on Sat 15th Sep, 2012
by Lee Grey
Commander solves the problem of object-creation order by using lazy initialisation - whoever
makes the first request for a Signal with a given key will bring about it's creation.
Listeners can be added to a Signal even before the dispatching class
has optionally defined the type-signature of the Signal
Usage:
// create Commander instances by key, or use the default instance
//default:
var cmd = Commander.getInstance();
//string key:
var cmd = Commander.getInstance( 'specificCommander' );
var cmd = Commander.getInstance( 'ui' );
var cmd = Commander.getInstance( 'sfx' );
//use class as key:
var cmd = Commander.getInstance( MyClass );
//use instace as key:
var cmd = Commander.getInstance( someInstance );
//optional Signal definition for type safety:
cmd.defineSignal( 'someEvent', Number, Number );
//Cache references to signals for performance-critical situations
var someEventSignal:Signal = cmd.defineSignal( 'someEvent', Number, Number );
var someEventSignal:Signal = cmd.getSignal( 'someEvent' );
//add listeners:
cmd.add( 'someEvent', onSomeEventHandler );
cmd.addOnce( 'someEvent', onSomeEventHandler );
//add listener to a particular instance:
Commander.getInstance( instance ).add( 'someEvent', onSomeEventHandler );
//Cache references to signals for performance-critical situations:
var someEventSignal:Signal = cmd.defineSignal( 'someEvent', Number, Number );
var someEventSignal:Signal = cmd.getSignal( 'someEvent' );
//dispatch through Commander:
cmd.dispatch( 'someEvent', x, y );
// dispatch the cached signal:
someEventSignal.dispatch( x, y );
// dispatch for a specific instance:
Commander.getInstance( this ).dispatch( x, y );
Static signal groups:
Using statc groups ensures that signals are created and
available to the application immediately
//for class XYZ, create a static instance of a group of signals:
class XYZSignalGroup {
//use the class XYZ as a key:
private const cmd:Commander = Commander.getInstance( XYZ );
public const aSignal:Signal = cmd.defineSignal( 'someEvent', Number, Number );
public const bSignal:Signal = cmd.defineSignal( 'someOtherEvent', Number, Number );
}
// within XYZ class:
public static const signals:XYZSignalGroup = new XYZSignalGroup();
// now access signals like this:
XYZ.signals.aSignal.add( 'someEvent', handler );
// or...
Commander.getInstance( XYZ ).add( 'someEvent', handler );
// Alternatively, a group with static members:
class XYZSignals {
//use the class XYZSignals as a key:
private static const cmd:Commander = Commander.getInstance( XYZSignalGroup );
public static const aSignal:Signal = cmd.defineSignal( 'someEvent', Number, Number );
public static const bSignal:Signal = cmd.defineSignal( 'someOtherEvent', Number, Number );
}
//access like this:
XYZSignals.aSignal.add( 'someEvent', handler );
*/
package com.lgrey.signal {
import flash.utils.Dictionary;
import org.osflash.signals.Signal;
public class Commander {
private static var instances:Dictionary = new Dictionary();
private var signals:Dictionary = new Dictionary();
public function Commander()
{
}
/*public static function defineSignal( key:*, ...types ):Signal
{
}*/
//use defineSignal to create type safe signals
public function defineSignal( key:*, ...types ):Signal
{
var signal:Signal = signals[ key ];
//warn if overwriting
if( signal ) { // assert( signals[ key ], 'warning....' )
trace( 'Commander::defineSignal() - Warning, signal already existed for this key.'
+ ' Overwriting valueClasses.' );
} else {
signal = signals[ key ] = new Signal();
}
//set / update valueClasses
signal.valueClasses = types;
return signal
}
public function add( key:*, closure:Function ):Signal
{
var signal:Signal = signals[ key ];
if( !signal ) signal = signals[ key ] = new Signal();
signal.add( closure );
return signal;
}
public function addOnce( key:*, closure:Function ):Signal
{
var signal:Signal = signals[ key ];
if( !signal ) signal = signals[ key ] = new Signal();
signal.addOnce( closure );
return signal;
}
public function remove( key:*, closure:Function ):Signal
{
var signal:Signal = signals[ key ];
if( signal ) signal.remove( closure );
return signal;
}
// using apply() results in a significant performance hit
// in performance-critical situations, cache the Signal reference
// returned by defineSignal() and getSignal()
public function dispatch( key:*, ...args ):Signal
{
var signal:Signal = signals[ key ];
if( signal ) signal.dispatch.apply( null, args );
else trace( 'Commander::dispatch() - Warning, no signal with key:', key );
return signal;
}
public function getSignal( key:* ):Signal
{
var signal:Signal = signals[ key ];
if( !signal ) signal = signals[ key ] = new Signal();
return signal;
}
public static function getInstance( key:* = 'defaultInstance' ):Commander
{
var cmd:Commander = instances[ key ];
if( !cmd ) cmd = instances[ key ] = new Commander();
return cmd;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment