Since AS3 does not allow private constructors, it seems the only way to construct a singleton and guarantee the constructor isn't explicitly created via "new" is to pass a single parameter and check it.
I've heard two recommendations, one is to check the caller and ensure it's the static getInstance(), and the other is to have a private/internal class in the same package namespace.
The private object passed on the constructor seems preferable but it does not look like you can have a private class in the same package. Is this true? And more importantly is it the best way to implement a singleton?
A slight adaptation of enobrev's answer is to have instance as a getter. Some would say this is more elegant. Also, enobrev's answer won't enforce a Singleton if you call the constructor before calling getInstance. This may not be perfect, but I have tested this and it works. (There is definitely another good way to do this in the book "Advanced ActionScrpt3 with Design Patterns" too).
package {
public class Singleton {
private static var _instance:Singleton;
public function Singleton(enforcer:SingletonEnforcer) {
if( !enforcer)
{
throw new Error( "Singleton and can only be accessed through Singleton.getInstance()" );
}
}
public static function get instance():Singleton
{
if(!Singleton._instance)
{
Singleton._instance = new Singleton(new SingletonEnforcer());
}
return Singleton._instance;
}
}
}
class SingletonEnforcer{}
I've been using this for some time, which I believe I originally got from wikipedia of all places.
package {
public final class Singleton {
private static var instance:Singleton = new Singleton();
public function Singleton() {
if( Singleton.instance ) {
throw new Error( "Singleton and can only be accessed through Singleton.getInstance()" );
}
}
public static function getInstance():Singleton {
return Singleton.instance;
}
}
}
Here's an interesting summary of the problem, which leads to a similar solution.
You can get a private class like so:
package some.pack
{
public class Foo
{
public Foo(f : CheckFoo)
{
if (f == null) throw new Exception(...);
}
}
static private inst : Foo;
static public getInstance() : Foo
{
if (inst == null)
inst = new Foo(new CheckFoo());
return inst;
}
}
class CheckFoo
{
}
The pattern which is used by Cairngorm (which may not be the best) is to throw a runtime exception in the constructor if the constructor is being called a second time. For Example:
public class Foo {
private static var instance : Foo;
public Foo() {
if( instance != null ) {
throw new Exception ("Singleton constructor called");
}
instance = this;
}
public static getInstance() : Foo {
if( instance == null ) {
instance = new Foo();
}
return instance;
}
}