由于AS3.0本身不支持private/protected 构造器,所以实现一个singleton pattern很麻烦,必须采用曲线救国的方式。下面先列出几种实现方式,这几种方式都有一些漏洞。
(1)
因为构造器只检测caller是否等于Singleton.getInstance,来确保它只被实例化一次,这样传一个同样的参数进去来饶过检查,就不能保证实例化次数。如下:
(1)
- // faulty example
- package {
- public class Singleton {
- private static var singleton : Singleton;
- public static function getInstance() : Singleton {
- if ( singleton == null )
- singleton = new Singleton( arguments.callee );
- return singleton;
- }
- //NOTE: AS3 does not allow for private or protected constructors
- public function Singleton( caller : Function = null ) {
- if( caller != Singleton.getInstance )
- throw new Error ("Singleton is a singleton class, use getInstance() instead");
- if ( Singleton.singleton != null )
- throw new Error( "Only one Singleton instance should be instantiated" );
- //put instantiation code here
- }
- }
- }
- var a:Singleton = new Singleton(Singleton.getInstance);
- var b:Singleton = new Singleton(Singleton.getInstance);
- // a !== b
- (2)
- // faulty example
- package whatever {
- public class MySingleton {
- public function MySingleton(singletonEnforcer:MySingletonEnforcer) { }
- private static var instance:MySingleton;
- pubic function getInstance():MySingleton {
- if (instance == null)
- instance = new MySingleton(new MySingletonEnforcer());
- return instance;
- }
- }
- }
- //this is in MySingleton.as but is outside the package block
- class MySingletonEnforcer {}
这个办法也是《design pattern》列出的标准做法,通过传递package外的内部class,来确保
实例化的个数。作者提到这样不能避免别人传递null参数来绕开。如下:
var a:MySingleton = new MySingleton(null);
var b:MySingleton = new MySingleton(null);
// a !== b
如果在构造器裏加入检测传参是否是null的判断,就可以避免了。
- package whatever {
- public final class MySingleton {
- public function MySingleton(singletonEnforcer:MySingletonEnforcer) {
- if (singletonEnforcer == null) {
- throw new Error ("MySingleton is a singleton class, use getInstance() instead");
- }
- }
- private static var instance:MySingleton;
- public static function getInstance():MySingleton {
- if (instance == null)
- instance = new MySingleton(new MySingletonEnforcer());
- return instance;
- }
- }
- }
- //this is in MySingleton.as but is outside the package block
- class MySingletonEnforcer {}
例子1也可以用下面的方法完善:
- package {
- public final class Singleton {
- private static var singleton : Singleton;
- public static function getInstance() : Singleton {
- if ( singleton == null )
- singleton = new Singleton( hidden );
- return singleton;
- }
- private static function hidden():void {}
- //NOTE: AS3 does not allow for private or protected constructors
- public function Singleton( caller : Function = null ) {
- if( caller != hidden )
- throw new Error ("Singleton is a singleton class, use getInstance() instead");
- if ( Singleton.singleton != null )
- throw new Error( "Only one Singleton instance should be instantiated" );
- //put instantiation code here
- }
- }
- }
下面给出最简介的一种办法来实现:
这样做的妙处就在该单件类在被引用的时候,VM初始化过程中,静态变量为null而在构造器裏的检测
- package {
- public final class Singleton {
- private static var instance:Singleton = new Singleton();
- public function Singleton() {
- if( instance ) throw new Error( "Singleton and can only be accessed through Singleton.getInstance()" );
- }
- public static function getInstance():Singleton {
- return instance;
- }
- }
- }
并没有被触发,所以无法使用new()/ new(***)的办法来实例化,只能通过getInstance()来调用。
来源:http://life.neophi.com/danielr/2006/10/singleton_pattern_in_as3.html