单件(singleton)模式在c#中是最容易实现的模式,其主要用意就在于限制使用者用new来创建多个实例。但在as3中,构造函数必须是public的(语法本身要求的),而且也不能在构造函数中抛出异常(编译可通过,但是逻辑行不通),因为这样相当于把创建实例的路子完全切断了,一个实例也得不到!
错误代码:
package{ public class singleton{ static private var _instance:singleton; public function singleton():void{ throw Error("单件模式不能用new创建实例!"); } public static function getInstance():singleton{ if (_instance==null){ _instance = new singleton();//因为上面的构造函数抛出了异常,所以这里运行时会报错 } return _instance; } } }
怎样即能创建实例,又阻止使用者调用构造函数呢?这里要用到as3的一个特性:默认情况下,一个as文件,只能放一个类,而且必须用package声明,但有一种特殊情况:一个as文件中定义二个类,一个用package声明,一个不用!没有package的类,默认访问范围为“仅同在一个文件的类可访问”
package { public class SingletonFactory { private static var _instance:Singleton2=null; public function SingletonFactory():void { trace Error("error!"); } public static function getInstance():Singleton2 { if (_instance == null) { _instance=new Singleton2(); } return _instance; } } } class Singleton2 { import flash.utils.getTimer; private var _createTime:uint; public function Singleton2() { _createTime=getTimer(); } public function toString():String { return "本实例的创建时间:" + _createTime.toString(); } public function helloWorld(name:String):String { return "hello " + name + " !"; } }
测试:
package { import flash.display.Sprite; import flash.utils.getTimer; public class main extends Sprite { public function main() { var a:* = SingletonFactory.getInstance(); trace(getTimer()); var s1:* = SingletonFactory.getInstance(); trace(s1.toString()); //空循环,刻意占用cpu,消耗占时间而已 for(var i:uint=0;i<999999;i++) { //trace(); } trace(getTimer()); var s2:* = SingletonFactory.getInstance(); trace(s2.toString()); trace(s1==s2); trace(s1.helloWorld("jimmy")); } } }
但这里有一个不爽的地方,SingleTon2类离开了文件SingletonFactory.as就无法访问了,所以我们在使用时,只能用var s1:* 来声明,虽然可以使用,但是在fd,fb等编程环境中却无法获得代码自动感知!
可以借助接口改进一下:
package { public interface ISingleton { function toString():String; function helloWorld(name:String):String; } }
然后让SingleTon2实现该接口
package { public class SingletonFactory { private static var _instance:Singleton2=null; public function SingletonFactory():void { trace Error("error!"); } public static function getInstance():Singleton2 { if (_instance == null) { _instance=new Singleton2(); } return _instance; } } } class Singleton2 implements ISingleton //这里改为实现接口 { import flash.utils.getTimer; private var _createTime:uint; public function Singleton2() { _createTime=getTimer(); } public function toString():String { return "本实例的创建时间:" + _createTime.toString(); } public function helloWorld(name:String):String { return "hello " + name + " !"; } }
重新测试:
package { import flash.display.Sprite; public class main extends Sprite { public function main() { var s:ISingleton=SingletonFactory.getInstance(); trace(s.helloWorld("jimmy.yang")); } } }
当然明白了上面的原理后,其实可以更一步简化,既然不声明package的类,只能限制在同一个文件内部的其它类可以访问,何不把它做为构造函数的参数?(这样不就限制了从外部调用构造函数么)
package { public class Singleton2 { private static var _instance:Singleton2; public function Singleton2(n:_nothing) { } public static function getInstance():Singleton2{ if (_instance==null){ _instance = new Singleton2(new _nothing()); } return _instance; } } } class _nothing{}
这样就清爽多了,当然Singleton模式在AS3中的实现方法不止一种,下面这种也许更容易理解:
package{ public class Singleton{ private static var _instance:Singleton = null; public function Singleton(){ if(_instance == null){ _instance = this; }else{ throw Error("已经存在该类的实例!"); } } public static function getInstance():Singleton{ if(_instance != null){ return _instance; } return new Singleton(); } } }