Flash/Flex/AIR:ActionScript 2定时器--基于观察者模式的实现

2019-04-13 16:26发布

这是一个基于观察者模式而设计的ActionScript2定时器的完整源码 /** * (#)The Timer class used for fixed cycle operationg * @author WarGrey * @version 2.0 * @since ActionScript 2.0 * @see mx.events.EventDispatcher */ import mx.events.EventDispatcher;
class wargrey.util.Timer extends EventDispatcher{ public static var INITIATE:String="initiate"; public static var TIMECYCLE:String="timecycle"; public static var TERMINATE:String="terminate"; //This timer ID private var id:Number; //The repetition times that has happened after begin executing private var repetition:Number; //The interval of each repetition private var _interval:Number; public function get interval():Number{ return _interval; } //This variable is used to show whether the timer has launched. private var isLaunched:Boolean; public function Timer(interval:Number){ //Set the _interval with the default value is 1000 ms. _interval=(interval>0)?interval:1000; //The repetition times is cleared to 0 repetition=0; //The isLaunched is setted by false isLaunched=false; } //Begin to timing and dispatch the "initiate" event. public function start():Void{ var event:Object=new Object(); event.type="initiate"; event.target=this; event.interval=interval; dispatchEvent(event); isLaunched=true; id=setInterval(this,"run",interval); } //Stop the time and dispatch the "terminate" event. public function stop():Void{ clearInterval(id); isLaunched=false; var event:Object=new Object(); event.type="terminate"; event.target=this; event.times=repetition; repetition=0; dispatchEvent(event); } //Registe the observers only before this timer launched, or it will call the method named "addEventListenerFailed" of observer and return false; public function addEventListener(event:String,handler:Object):Boolean{ if (!isLaunched){ super.addEventListener(event,handler); return true; }else{ if (handler["addEventListenerFailed"]!=undefined){ var failure:Object=new Object(); failure.type=event; failure.target=this; failure.times=repetition; handler.addEventListenerFailed(failure); } return false; } } //Execute the repetition method which dispatches the "timecyle" event. private function run():Void{ repetition++; var event:Object=new Object(); event.type="timecycle"; event.target=this; event.times=repetition; dispatchEvent(event); } public function toString():String{ if (id==undefined){ var msg="unlaunched"; }else{ var msg="Timer["+id.toString()+"]"; } return msg; } } 该定时器类Timer继承于mx.events.EventDispatcher,这样一来便成了一个功能完善的广播源,代码书写上也比混入更清晰易懂。既然是基于观察者模式的定时器,现在又有了广播源,那当然也需要一个观察者通过timer.addEventListenertimer.removeEventListener等方法来注册取消感兴趣的事件。对于一般的面向对象语言,对于观察者和广播源必须专门定制,或通过其他机制来实现,因此或多或少会造成了性能损失,不过ActionScript2也是一个相当不错的动态语言,处理类似的问题具有先天的优势,因此任何一个Object都可以充当任何广播源的观察者,自然对于定时器类来说,其提供的三个事件,即initiatetimecycleterminate,因此它的观察者应至少提供其中的一个方法才能正确注册。当然不提供也行,那样Timer就当注册没发生。下面详细介绍观察者的可选方法: initiate事件:对应于Timer.INITIATE静态成员,是启动定时器时广播的事件。 timercycle事件:对应于Timer.TIMERCYCLE静态成员,是每次定时重新执行时广播的事件。 terminate事件:对应于Timer.TERMINATE静态成员,是停止定时器时广播的事件。 addEventListenerFailed事件:当注册事件失败时广播此事件。为了避免混乱,该定时器规定只有当定时器未启动时才能注册事件,所以如果注册事件时定时器已经启动便会导致注册事件失败。 对于所有事件,都有一个Object类型的参数,该参数包含如下属性:
  • type:事件名称。
  • target:广播源对象实例。
  • interval:仅限于initiate事件,该定时器实例定时时间间隔。
  • timesinitiate事件不适用,到目前为止定时器重复执行的次数。
下面是个测试用例,为方便测试做成了Flash SWC组件。 //The First Observer class wargreytest.util.timer.TimerTestObject { private var name; public function TimerTestObject(name:String){ this.name=(name.length>0)?name:"default"; } private function initiate(event:Object):Void{ _root.display(name+" has launched."); _root.newLine(); } private function timecycle(event:Object):Void{ _root.display(name+" recycled for "+event.times.toString()+" times."); _root.newLine(); } private function terminate(event:Object):Void{ _root.display(name+" has terminated."); _root.newLine(); } }
//The Second Observer import wargreytest.util.timer.*; class wargreytest.util.timer.TimerTestObject2 extends TimerTestObject{ public function TimerTestObject2(name:String){ super(name); } private function addEventListenerFailed(event:Object):Void{ _root.display(name+" registe '"+event.type+"' listener failed."); _root.newLine(); } }
//The Timer TestCase Component import wargreytest.util.timer.*; import wargrey.util.*; import wargrey.extension.GraphicalInterface; [InspectableList("interval","instanceno","seconds")] class wargreytest.util.TimerTest extends MovieClip{ private var id:Number; private var timer:Timer; private var _interval:Number; [Inspectable(name="interval",defaultValue="1000",verbose=0)] public function set interval(itl:Number):Void{ _interval=(itl>0)?itl:1000; } public function get interval():Number{ return _interval; } private var _instanceno:Number; [Inspectable(name="instanceno",defaultValue="3",verbose=0)] public function set instanceno(isn:Number):Void{ _instanceno=(isn>0)?isn:3; } public function get instanceno():Number{ return _instanceno; } private var _seconds:Number; [Inspectable(name="seconds",defaultValue="5",verbose=0)] public function set seconds(s:Number):Void{ _seconds=(s>0)?s:5; } public function get seconds():Number{ return _seconds; } private function onLoad():Void{ this._visible=false; var gi:GraphicalInterface=new GraphicalInterface(); gi.extend(_root); timer=new Timer(interval); for (var i=instanceno-1;i>=0;i--){ var temp:TimerTestObject=new TimerTestObject("timeListener"+i.toString()); timer.addEventListener("initiate",temp); timer.addEventListener("timecycle",temp); timer.addEventListener("terminate",temp); } timer.start(); id=setInterval(this,"stopTest",seconds*1000); var temp:TimerTestObject=new TimerTestObject("timeListener"+instanceno.toString()); timer.addEventListener("initiate",temp); var temp:TimerTestObject=new TimerTestObject2("timeListener"+(instanceno+1).toString()); timer.addEventListener("timercycle",temp); } private function stopTest():Void{ timer.stop(); clearInterval(id); } } 补充说明:定时器的定时时间间隔只能在构造Timer实例时指明,以后便不能更改,若构造时省略则默认为1000,单位毫秒。