Anyone who has ever even heard of the illustrious Gang of Four has heard of the Singleton pattern. To those of you who have not heard of this pattern, the idea is this: You have a class which will instantiate itself once, and only once. An immediate Actionscript example that comes to mind is the Stage or root. No matter what happens, there will only ever be one root.

The Singleton pattern is able to do certain things very well: control the stage, for example; and I find the article http://www.actionscript.org/resources/articles/610/1/Centralized-Event-Management-in-Actionscript-20/Page1.html on centralized event managing to be particularly useful. But there are certain limitations to the Singleton as well which will be discussed below.

Unfortunately, there are no protected constructors in AS3 (which is why Java can subclass Singleton with comparable ease). So the most common way to accomplish the Singleton pattern is to require the constructor to take a parameter which cannot be met:

package{
public class Singleton{
private static var _instance:Singleton = null;

// Because this requires PrivateClass, it cannot be instantiated from the outside.
public function Singleton (pvt:PrivateClass){
}

// Static functions, because they belong to the class, can be called without instantiation.
public static function getInstance():Singleton{
if (_instance == null){
_instance = new Singleton(new PrivateClass());
}
return _instance;
}
}
}
/*
* This class cannot be imported so it can only be accessed within this particular as file.
*/

class PrivateClass{
function PrivateClass(){}
}


The biggest issue is that there is the lack of an ability to subclass it – something which proves very difficult down the line. And there are some notable workarounds. One of the better ones was akin to this:

package{
public class Singleton{
private static var _instance:Singleton = null;
private static var allowInstance:Boolean;

// Because this requires PrivateClass, it cannot be instantiated from the outside.
public function Singleton (){
if (!allowInstance) {
throw new Error ('This class cannot be instantiated from the constructor');
}
}

public static function getInstance():Singleton{
if (_instance == null){
allowInstance = true;
_instance = new Singleton();
allowInstance = false;
}
return _instance;
}
}
}

But this has an apparent drawback as well: it will not generate compile-time errors. Because it is dependent on a run-time verification of its singularity, the compiler lets it pass. So you are left with a choice: do you want compile time errors (which would allow you to see, immediately, the effects of trying to re-instantiate the class) or do you want to be able to extend the class?

One solution, proposed back in 2001 by an Alex Martelli (http://code.activestate.com/recipes/66531/), was the “Borg” class. Have the ability to continually re-instantiate, but have all of the internal variables be exactly the same. The most immediately obvious rendering of this class is the following:

package {
public class Borg {
protected static var _variables:Array;

public function Borg(){
}

public function set foo(obj:Object){
_variables['foo'] = obj;
}
}
}


Effectively, all of the variables would be stored in one central space, shared by all instances. There are several difficulties here though. First, there is no way to ensure that a value remains typed. This means that I could accidentally set what I thought was a string 'bar' into a number or a MovieClip. You could try to do something like:

public function Borg () {
_variables['foo'] = {type:'object', obj:}
_variables['bar'] = {type:'number', obj:}
}


But you'd have to enforce this via manual type-checking, and that is shotty at best – typeof will not work with non-native classes. Your best is to try, if (Class(obj) === Class(obj2)), but this is seriously imitted.

There is, however, one way to ensure that all variables will be properly set and stored: a library class. The trick to realizing both the practical applied needs for a Singleton and the GoF's definition is not found within one class in AS3, it is found in two.

The key to the Singleton is not entirely instantiation of one class. The key to Singleton is that it allows global access to the same object. That may sound confusing, but bear with me.

Imagine this: you have a Borg class, but instead of having everything stored in an Array, you have everything stored in an independent, static instance of a library class. That way, the Library (or, I suppose if we were to take the sci-fi references ad nauseum, the “hive mind”) would be encapsulated and inaccessible to every non-member. If someone wanted to create another instance of the Library it is functionally irrelevant. Theoretically, it might be possible to even write such a library which would be useful outside of the context of the aforementioned network.

This is a potential example of the classes. The library class could work as a functional class in any number of circumstances but in this particular circumstance it will function solely as a private central library to the Borg class.
package {
public class Borg {
protected static var _lib:Library;

public function Borg(){
if (Borg._lib == undefined) Borg._lib = new Library();
// The rest of my code
}

public function set foo(obj:Object){
_lib.foo = obj;
}
}
}

package {
import flash.utils.Dictionary; // A Hash class.

public class Library {
private var publicDic:Dictionary;
private var privateDic:Dictionary;
private var checkedOut:Array;

public function Library(){
}

public function checkOut(key:Object):*{
for (var i:uint = 0; i < checkedOut.length; i++){
if (checkedOut[i] === key) throw new Error('Cannot check out key: ' + key + '. Please check it in first');
}
if ((privateDic[key] != undefined ) && (privateDic[key] != null )) {
checkedOut.push(key);
return privateDic[key];
}
throw new Error('Cannot check key ' + key);
}

public function checkIn(key:Object, value:Object):void{
if(privateDic[key] !== value)throw new Error('Key value match failure.');
var res:int = 0;
for (var i:uint = 0; i < checkedOut.length; i++){
if (checkedOut[i] === key) res = i;
}
checkedOut.splice(res,1);
}

public function createPrivateVar(key:Object, value:Object):void{
privateDic[key] = object;
}

public function createPublicVar(key:Object, value:Object):void{
publicDic[key] = object;
}

public function getPublicVar(key:Object):*{
return publicDic[key];
}
}
}

As you can see, since nothing outside of the Borg class has access to the _lib object; thus, the object is a de facto Singleton. This means that, given the proper structuring of code, you will be able to accomplish all of the requisites of Singleton without compromising the ability to sub-class and without removing eventual ability to say (as the GoF suggests as a possibility) create multiple instances (in this case, it is as simple as removing 'static').

Obviously, the above code cannot truly replace the Singleton, but hopefully, this will provide an avenue of escape, or rather prevent at least some from falling into the AS3 Singleton trap and therefore the massive restructuring of code.

-- CW Allen-Poole.
(Please watch rosettastone.allen-poole.com by early September).