Upload
marc-alcaraz
View
214
Download
0
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_pattern8/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 ;
}}
}}