AS3的单例模式

AS3的单例模式

关于单例模式,网上很多了。我个人喜欢这样写:

 package {
    public class Singleton {
        private static var singleton : Singleton;
        private static var key:Boolean=false;

       public static function getInstance() : Singleton {
            if ( singleton == null ){
                 key=true;
                singleton = new Singleton();
            }
            return singleton;
        }

        public function Singleton( ) {      
            if( !key ){
                throw new Error ("单例,请用 getInstance() 取实例。");
            }
            key=false;

        }
    }
}


以下这篇文章讲到实现单例模式的几种方法。来自:
http://life.neophi.com/danielr/2006/10/singleton_pattern_in_as3.html
因为经常访问不到,所以贴到这里来。

Singleton Pattern in AS3

AS3 does not support private or protected constructors which makes it harder to implement the singleton pattern. Below are some approaches I've run across on the Internet, problems with them, and what I hope (please tell me if I'm wrong) corrections to get a real singleton pattern working.

First up is an entry by Andrew Trice about Singletons in AS3. His code was:

// 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
}
}
}

You can defeat this approach with:

var a:Singleton = new Singleton(Singleton.getInstance);
var b:Singleton = new Singleton(Singleton.getInstance);
// a !== b

The constructor is doing a function reference comparison, but the function being compared to is available to the caller which is why it can be passed in to defeat the test.

I was also pointed at an approach created by Matt Chotin and posted to Flex Coders. This is a direct cut'n'paste so there are some syntax errors.

// 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 {}

 

You can defeat this approach with:

var a:MySingleton = new MySingleton(null);
var b:MySingleton = new MySingleton(null);
// a !== b

If you don't know about private classes I wrote up some information. This is just a missing null check in the constructor to make sure that a valid reference was passed in. I like this approach better overall since it has more compile time support. Trying to call "new MySingleton()" gives an "expected 1 argument" compile time error and trying to call "new MySingleton(XXX)" with anything but null will give you a class cast exception. But that is my personal preference.

I'd also recommend that you add final to the class definition. While I'm pretty sure you can't get access to stuff that easily in AS3, it is probably best to guard against subclassing.

If you want to use the first approach, it can be fixed with the introduction of a private method:

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
}
}
}

The second approach can be fixed with the introduction of a null check:

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 {}

 

This final example, which I think is best, comes from Daniel Hai via Ted Patrick's JAM. The entry is "Singleton Take 2":


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;
}
}
}

 

I've updated Wikipedia with this last example. Please change it if you notice any problems.




[本日志由 jackgun 于 2007-10-24 11:47 AM 编辑]
文章来自: 本站原创
引用通告: 查看所有引用 | 我要引用此文章
Tags: singleton pattern as3 单态
相关日志:
评论: 0 | 引用: 0 | 查看次数: -
发表评论
昵 称:
密 码: 游客发言不需要密码.
内 容:
验证码: 验证码
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.