Signals and Receivers

Embed Size (px)

Citation preview

  • 8/8/2019 Signals and Receivers

    1/10

    Signals & Receivers

    Generality

    The "signal engine" include in the package system.signals is a very easy ActionScript3messaging tools.

    With the Signaler interface we can define objects who communicates by signals and can be use

    to create a light-weight implementation of the Observer pattern. A signal emit simple values withits own array of receivers (slots). This values can be strongly-typed with an internal checking

    process.

    Receivers can be defines with a simple function reference or a custom object who implementsthe interface system.signals.Receiver .

    Receivers subscribe to real objects, not to string-based channels. Event string constants are no

    longer needed like W3C DOM 2/3 event model.

    Interfaces

    The system.signals package contains two interfaces : Signaler and Receiver.

    The Signaler interface is simple but contains all important methods to deploy your signals.

    package system.signals

    {

    publicinterface Signaler

    {

    /**

    * Indicates the number of receivers connected.

    */

    function get length():uint ;

    /**

    * Connects a Function reference or a Receiver object.

    * @param receiver The receiver to connect : a Function reference or aReceiver object.

    * @param priority Determinates the priority level of the receiver.

    * @param autoDisconnect Apply a disconnect after the first trigger

    http://en.wikipedia.org/wiki/Observer_patternhttp://en.wikipedia.org/wiki/Observer_pattern
  • 8/8/2019 Signals and Receivers

    2/10

    * @return true If the receiver is connected with the signal emitter.

    */

    function connect( receiver:* , priority:uint = 0 , autoDisconnect:Boolean =false ):Boolean ;

    /**

    * Returns true if one or more receivers are connected.

    * @return true if one or more receivers are connected.

    */

    function connected():Boolean ;

    /**

    * Disconnect the specified object or all objects if the parameter is null.

    * @return true if the specified receiver exist and can be unregister.

    */

    function disconnect( receiver:* = null ):Boolean ;

    /**

    * Emit the specified values to the receivers.

    * @param ...values All values to emit to the receivers.

    */

    function emit( ...values:Array ):void ;

    /**

    * Returns true if specified receiver is connected.

    * @return true if specified receiver is connected.

    */

  • 8/8/2019 Signals and Receivers

    3/10

    function hasReceiver( receiver:* ):Boolean ;

    }

    }

    The Receiver interface is optional and can be use to defines a basic slot connected with Signaler

    objects with the connect() method (only the receive method is connected with the signal not theReceiver reference).

    package system.signals{

    /*** The Receiver defines a simple method for receiving values from Signaler.*/

    publicinterface Receiver{

    /*** This method is called when the receiver is connected with a Signal

    object. * @param ...values All the values emitting by the signals connected withthis object.

    */ function receive( ...values:Array ):void ;

    }}

    Hello World

    We begin with a first basic example. In this example we use the system.signals.Signal, this

    class is a basic but full implementation of the Signaler interface. This script can be compiled asan application with mxmlc or as a document class in Flash Professional or all ActionScript IDE

    (FDT, etc.)

    package examples{ import system.signals.Signal;

    import flash.display.Sprite;

    [SWF(width="740", height="480", frameRate="24", backgroundColor="#666666")]

    publicclass SignalExample extends Sprite{

    publicfunction SignalExample ()

    { var signal:Signal = new Signal() ;

    signal.connect( write ) ;

    signal.emit( "hello world" ) ; // hello worldsignal.emit( "thank you" ) ; // thank you

    }

    publicfunction write( message:String ):void{

  • 8/8/2019 Signals and Receivers

    4/10

    trace( message ) ;}

    }}

    Features

    Signals have many features.

    Restrict the types and the number of arguments passed-in the emit

    method.

    A signal can be initialized with specific value classes that will validate value objects on dispatch

    (optional).

    The 'types' property is an optional read-write Array attribute who can register Class references todefines a validation when the signal emit. If this property is null the signal not check the emit

    parameters.

    var signal:Signal = new Signal([ String , Number , uint ] ) ;

    trace( "restricted types : " + signal.types ) ;

    If the 'types' property is null the signal not check the types and the number of the passed-inarguments when the emit method is invoked.

    Basic example to restrict the emit method with 3 arguments with the types String , Number and

    uint.

    import system.signals.Signal ;

    var slot:Function = function( ...values:Array ):void{

    trace("receive : " + values ) ;}

    var signal:Signal ;

    signal = new Signal() ;

    signal.types = [ String , Number , uint ] ;

    signal.connect( slot ) ;

    signal.emit( "hello" , 2.5, 4 ) ; // receive : hello,2.5,4

    try{

    signal.emit( "hello" , 2.5 , 4.5 ) ;}catch( e:Error )

  • 8/8/2019 Signals and Receivers

    5/10

    { trace( e.message ) ;

    // The parameter with the index 2 in the emit method isn't valid,// must be an instance of the [class uint] class but is an instance of the

    Number class.}

    try

    {signal.emit( "hello" ) ;

    }catch( e:Error ){ trace( e.message ) ;

    // The number of arguments in the emit method is not valid,// must be invoked with 3 arguments and you call it with 1 argument.

    }

    try{

    signal.emit() ;

    }catch( e:Error ){ trace( e.message ) ;

    // The number of arguments in the emit method is not valid,// must be invoked with 3 arguments and you call it with 0 argument.

    }

    Disconnect a specific receiver or all receiver

    You can disconnect the receivers registered in a Signaler object with the method disconnect().This method can target a specific receiver (function reference or Receiver instance) but you can

    disconnect all registered receivers if you don't passed-in value.

    Example :

    import system.signals.Signal ;

    var signal:Signal = new Signal() ;

    signal.connect( slot1 ) ;signal.connect( slot2 ) ;signal.connect( slot3 ) ;

    trace( signal.length ) ; // 3

    signal.disconnect( slot2 ) ;

    trace( signal.length ) ; // 2

    signal.disconnect() ; // disconnect all

    trace( signal.length ) ; // 0

  • 8/8/2019 Signals and Receivers

    6/10

    Note :

    You can retrieve the number of receivers with the read-only attribute : signal.length

    You can retrieve if the signal contains one or more receivers with the method :signal.connected():Boolean

    You can retrieve if a specific receiver is connected with the method :

    signal.hasReceiver( receiver:* ):Boolean

    Auto disconnect feature

    Receivers can be added for a one-time call and removed automatically on dispatch

    import system.signals.Signal ;

    var receiver:Function = function( message:String ):void{

    trace( message ) ;

    }

    var signal:Signal = new Signal() ;

    signal.connect( receiver , 0 , true ) ;

    signal.emit( "hello world" ) ; // hello worldsignal.emit( "bonjour monde" ) ;

    Only the first message is dispatched, the reveiver is automatically disconnected and can't receive

    the next messages.

    Receiver priority

    When you connect a receiver with the connect method you can apply a priority over your

    reference.

    The priority is designated by an uint value( an integer > 0 ). The higher the number, the higher

    the priority. All receivers with priority n are processed before receivers of priority n-1. If two ormore receivers share the same priority, they are processed in the order in which they were added.

    The default priority is 0.

    import system.signals.Signal ;

    var slot1:Function = function( message:String ):void

    { trace( "slot1: " + message ) ;}

    var slot2:Function = function( message:String ):void{ trace( "slot2: " + message ) ;}

    var slot3:Function = function( message:String ):void{

  • 8/8/2019 Signals and Receivers

    7/10

    trace( "slot3: " + message ) ;}

    var signal:Signal = new Signal() ;

    signal.connect( slot1 , 10 ) ;signal.connect( slot2 , 999 ) ;signal.connect( slot3 , 400 ) ;

    signal.emit( "hello world" ) ;

    // slot2: hello world// slot3: hello world// slot1: hello world

    Use composition with the system.signals.Signaler interface

    package examples.signals{ import system.signals.Signal; import system.signals.Signaler;

    import flash.display.Sprite; import flash.events.MouseEvent;

    publicclass SignalButton extends Sprite implements Signaler{

    public function SignalButton( width:Number = 160 , height:Number = 20 ,color:Number = 0xA2A2A2 ):void

    {_signal = new Signal( [ String , SignalButton ] ) ;addEventListener( MouseEvent.CLICK , _click ) ;graphics.beginFill( color ) ;graphics.drawRect( 0 , 0 , width , height ) ;

    buttonMode = true ;mouseEnabled = true ;useHandCursor = true ;

    }

    public functionget length():uint ;{

    return _signal.length ;}

    public function connect( receiver:* , priority:uint = 0 ,autoDisconnect:Boolean = false ):Boolean

    { return _signal.connect( receiver , priority , autoDisconnect ) ;

    }

    public function connected():Boolean{

    return _signal.connected() ;}

    public function disconnect( receiver:* = null ):Boolean{

    return _signal.disconnect( receiver ) ;}

  • 8/8/2019 Signals and Receivers

    8/10

    public function emit( ...values:Array ):void{

    _signal.emit.apply( values ) ;}

    public function hasReceiver( receiver:* ):Boolean{

    return _signal.hasReceiver( receiver )}

    private var _signal:Signal ;

    private function _click( e:MouseEvent ):void{

    _signal.emit( "click" , this ) ;}

    }}

    Now we can write a little example to use the previous class :

    package examples{ import examples.signals.SignalButton;

    import flash.display.Sprite;

    [SWF(width="760", height="480", frameRate="24", backgroundColor="#666666")]

    public class SignalButtonExample extends Sprite{

    publicfunction SignalButtonExample(){

    var button:SignalButton = new SignalButton( 200 , 24 , 0xCCCCCC ) ;

    button.x = 25 ;button.y = 24 ;

    button.connect( notify ) ;

    addChild( button ) ;

    }

    publicfunction notify( type:String , target:SignalButton ):void{

    trace( "notify : " + type + " in " + target ) ;

    }}

    }

    Basic example to use the system.signals.Receiver interface

    First we defines a little class Messenger who format a specific receiving message with a name and

    a string pattern.

  • 8/8/2019 Signals and Receivers

    9/10

    package examples.signals{ import core.strings.fastformat;

    import system.console; import system.signals.Receiver;

    publicclass Messenger implements Receiver{

    public function Messenger( pattern:String = "{0}:{1}" ):void{

    this.pattern = pattern ;}

    public var pattern:String ;

    public function receive( ...values:Array ):void{

    var name:String = values[0] as String ;

    var message:String = values[1] as String ;

    console.writeLine( fastformat( pattern , name , message ) ) ;}

    }}

    Now the document class to compile the basic example.

    package examples{ import examples.signals.Messenger;

    import system.console; import system.diagnostics.TextFieldConsole; import system.signals.Signal;

    import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import flash.text.TextField; import flash.text.TextFormat;

    [SWF(width="760", height="480", frameRate="24", backgroundColor="#666666")]

    publicclass MessengerExample extends Sprite{

    public function MessengerExample(){

    // stage

    stage.align = StageAlign.TOP_LEFT;stage.scaleMode = StageScaleMode.NO_SCALE;

  • 8/8/2019 Signals and Receivers

    10/10

    stage.addEventListener( Event.RESIZE , resize ) ;

    // console

    textfield = new TextField() ;textfield.defaultTextFormat = new TextFormat( "Courier New" , 14 ,

    0xFFFFFF ) ;

    textfield.multiline = true ;textfield.selectable = true ;textfield.wordWrap = true ;

    addChild( textfield ) ;

    resize() ;

    console = new TextFieldConsole( textfield ) ;

    // receiver

    var messenger:Messenger = new Messenger( "{0} say: {1}" ) ;

    // signaler

    signal = new Signal([String,String]) ;

    signal.connect( messenger ) ;

    signal.emit( "john" , "hello world" ) ;signal.emit( "jack" , "Hi !" ) ;signal.emit( "jack" , "signals are fast" ) ;

    }

    public var signal:Signal ;

    public var textfield:TextField ;

    public function resize( e:Event = null ):void{

    if ( stage && textfield ){

    textfield.width = stage.stageWidth ;textfield.height = stage.stageHeight ;

    }}

    }}