The AS3 Singleton Revisited
Originally posted 29NOV07 on onebyonedesign.com.
It seems since the release of AS3, there has been much public debate on how to construct a good Singleton. For those wondering, the Singleton is a design pattern which allows for only a single instantiation of a particular class to take place. This is particularly useful for manager objects or for other items you may only want one of at any given time (tooltips, media players, etc.). In most languages, the Singleton is created using a private constructor method accessed by a static method of the Singleton class. Ecmascript (and hence Actionscript 3) does not allow for private constructors, however, so other ingenious methods have been devised for simulating such a thing. The most common one is to create a second class in the same .as file as the Singleton class and passing an instance within the Singleton’s constructor. Because of the way actionscript operates, any additional classes in one .as file can only be accessed by the main class in that file. They are then, in essence, private classes. There have been some arguments against this method though – the biggest being that having two classes in the same file is a bit of a design faux pas. This then is my take on the subject. I decided to go with the little used arguments array to pass a reference to the calling function to the Singleton’s constructor to guarantee only a single instance. A quick example:
/** * Singleton example using arguments.callee * property to enforce single instantiation. * @author Devon O. */ package { public class Singleton { private static var _thisInstance:Singleton; public function Singleton(caller:Function) { if (!(caller == makeInstance)) { // throw error } else { // instantiate it up } } public static function getInstance():Singleton { if (!_thisInstance) _thisInstance = Singleton.makeInstance(); return _thisInstance; } private static function makeInstance():Singleton { return new Singleton(arguments.callee); } } }
To use it, you simply create your object with:
var mySingleton:Singleton = Singleton.getInstance();
Unfortunately this approach calls for an additional private method (makeInstance()) to get the job done, but it at least requires only a single class rather than using a private “helper” class.