单件(singleton)模式在c#中是最容易实现的模式,其主要用意就在于限制使用者用new来创建多个实例。但在as3中,构造函数必须是public的(语法本身要求的),而且也不能在构造函数中抛出异常(编译可通过,但是逻辑行不通),因为这样相当于把创建实例的路子完全切断了,一个实例也得不到!
作者:菩提树下的杨过
出处:http://yjmyzz.cnblogs.com
错误代码:
1 package{ 2 public class singleton{ 3 4 static private var _instance:singleton; 5 6 public function singleton():void{ 7 throw Error("单件模式不能用new创建实例!"); 8 } 9 10 public static function getInstance():singleton{ 11 if (_instance==null){ 12 _instance = new singleton();//因为上面的构造函数抛出了异常,所以这里运行时会报错 13 } 14 return _instance; 15 } 16 17 } 18 }
怎样即能创建实例,又阻止使用者调用构造函数呢?这里要用到as3的一个特性:默认情况下,一个as文件,只能放一个类,而且必须用package声明,但有一种特殊情况:一个as文件中定义二个类,一个用package声明,一个不用!没有package的类,默认访问范围为“仅同在一个文件的类可访问”
1 package 2 { 3 4 public class SingletonFactory 5 { 6 private static var _instance:Singleton2=null; 7 8 public function SingletonFactory():void 9 { 10 trace Error("error!"); 11 } 12 13 public static function getInstance():Singleton2 14 { 15 if (_instance == null) 16 { 17 _instance=new Singleton2(); 18 } 19 return _instance; 20 } 21 } 22 } 23 24 class Singleton2 25 { 26 import flash.utils.getTimer; 27 28 private var _createTime:uint; 29 30 public function Singleton2() 31 { 32 _createTime=getTimer(); 33 } 34 35 public function toString():String 36 { 37 return "本实例的创建时间:" + _createTime.toString(); 38 } 39 40 public function helloWorld(name:String):String 41 { 42 return "hello " + name + " !"; 43 } 44 }
测试:
1 package 2 { 3 import flash.display.Sprite; 4 import flash.utils.getTimer; 5 6 public class main extends Sprite 7 { 8 public function main() 9 { 10 var a:* = SingletonFactory.getInstance(); 11 trace(getTimer()); 12 13 var s1:* = SingletonFactory.getInstance(); 14 trace(s1.toString()); 15 16 //空循环,刻意占用cpu,消耗占时间而已 17 for(var i:uint=0;i<999999;i++) 18 { 19 //trace(); 20 } 21 22 trace(getTimer()); 23 var s2:* = SingletonFactory.getInstance(); 24 trace(s2.toString()); 25 26 trace(s1==s2); 27 28 trace(s1.helloWorld("jimmy")); 29 30 31 } 32 } 33 }
但这里有一个不爽的地方,SingleTon2类离开了文件SingletonFactory.as就无法访问了,所以我们在使用时,只能用var s1:* 来声明,虽然可以使用,但是在fd,fb等编程环境中却无法获得代码自动感知!
可以借助接口改进一下:
1 package 2 { 3 public interface ISingleton 4 { 5 function toString():String; 6 7 function helloWorld(name:String):String; 8 } 9 }
然后让SingleTon2实现该接口
1 package 2 { 3 4 public class SingletonFactory 5 { 6 private static var _instance:Singleton2=null; 7 8 public function SingletonFactory():void 9 { 10 trace Error("error!"); 11 } 12 13 public static function getInstance():Singleton2 14 { 15 if (_instance == null) 16 { 17 _instance=new Singleton2(); 18 } 19 return _instance; 20 } 21 } 22 } 23 24 class Singleton2 implements ISingleton //这里改为实现接口 25 { 26 import flash.utils.getTimer; 27 28 private var _createTime:uint; 29 30 public function Singleton2() 31 { 32 _createTime=getTimer(); 33 } 34 35 public function toString():String 36 { 37 return "本实例的创建时间:" + _createTime.toString(); 38 } 39 40 public function helloWorld(name:String):String 41 { 42 return "hello " + name + " !"; 43 } 44 }
重新测试:
1 package 2 { 3 import flash.display.Sprite; 4 5 public class main extends Sprite 6 { 7 public function main() 8 { 9 var s:ISingleton=SingletonFactory.getInstance(); 10 trace(s.helloWorld("jimmy.yang")); 11 } 12 } 13 }
当然明白了上面的原理后,其实可以更一步简化,既然不声明package的类,只能限制在同一个文件内部的其它类可以访问,何不把它做为构造函数的参数?(这样不就限制了从外部调用构造函数么)
1 package 2 { 3 public class Singleton2 4 { 5 private static var _instance:Singleton2; 6 7 public function Singleton2(n:_nothing) 8 { 9 10 } 11 12 public static function getInstance():Singleton2{ 13 if (_instance==null){ 14 _instance = new Singleton2(new _nothing()); 15 } 16 return _instance; 17 } 18 } 19 } 20 21 class _nothing{}
这样就清爽多了,当然Singleton模式在AS3中的实现方法不止一种,下面这种也许更容易理解:
1 package{ 2 3 public class Singleton{ 4 5 private static var _instance:Singleton = null; 6 7 public function Singleton(){ 8 if(_instance == null){ 9 _instance = this; 10 }else{ 11 throw Error("已经存在该类的实例!"); 12 } 13 } 14 15 public static function getInstance():Singleton{ 16 if(_instance != null){ 17 return _instance; 18 } 19 return new Singleton(); 20 } 21 22 } 23 }
作者:菩提树下的杨过
出处:http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。