Singletons in ActionScript 3

by Pandafox | Posted in ActionScript 3, Tutorials

The singleton design pattern is an effective way to ensure that a class has only one instance. Let’s say you are writing a game and you want to have one main object that contains data that you need to access from many of your other objects. You could of course store a pointer to the main object in all of your other objects like this:

public class Game
{
    private var m_num:int;
    public function Game()
    {
        m_num = 5;
    }
    
    public function get num():int
    {
        return m_num;
    }

    public function addNum():void
    {
        m_num++;
    }
}

public class Foo
{
    private var m_game:Game;
    public function Foo(game:Game)
    {
        m_game = game;
    }

    public function cake():void
    {
        trace("Cake: " + m_game.num.toString());
        m_game.addFoo();
    }
}

public class Bar
{
    private var m_game:Game;
    public function Bar(game:Game)
    {
        m_game = game;
    }

    public function onion():void
    {
        trace("Onion: " + _game.num.toString());
        m_game.addFoo();
    }
}

As you can see, having to set up “m_game” in every instance can get pretty messy after a while.

Static Variables

What we’re going to do, to fix this problem is to take advantage of static variables. In case you don’t know what static variables are, have a look at this piece of code:

public class Test
{
	private static var m_foo:int; 
	public function talk():void
	{
		m_foo++;
		trace(m_foo);
	}
}

As you can see, we declare a static variable called m_foo. This variable will be shared by all instances of this class. So if we were to run this little piece of code:

var a:Test = new Test();
var b:Test = new Test();
a.talk();
b.talk();
a.talk();

Then the output would be:

1
2
3

Static Methods

To implement our singleton pattern properly, we will also have to use static methods. Static methods are methods which can be called without having to instantiate an object before calling it. By making the “talk” method from the previous example static, we could have our program count without having to waste time and memory on storing pointers all over the place:

public class Test
{
	private static var m_foo:int; 
	public static function talk():void
	{
		m_foo++;
		trace(m_foo);
	}
}

Counting from 1 to 3 with this class, is as easy as:

Test.talk();
Test.talk();
Test.talk();

And yes, the output will indeed be:

1
2
3

The Singleton Instance

Ok, now that we all know how static methods and variables can be used, we’re ready to implement our singleton pattern. So let’s start fixing up the Game-class from our first example:

public class Game
{
    private static var m_instance:Game;
    private var m_num:int;

    public function Game()
    {
        m_num = 5;
    }

    public static function get instance():Game
    {
        if (!m_instance) m_instance = new Game();
        return m_instance; 
    } 
}

This game-class has a static variable, m_instance, which is used to store a reference to an instance of itself. The game instance should only be retreived through Game.instance() and not by calling new Game(). This is because Game.instance() will call new Game() for us (if the instance doesn’t already exist) and return the static instance.

public class Game
{
    private static var m_instance:Game;
    private var m_players:Array;

    public function Game()
    {
        m_players = new Array();
    }

    public static function get instance():Game
    {
        if (!m_instance) m_instance = new Game();
        return m_instance; 
    } 

    public function add_player(name:String):void
    {
        m_players.push(name);
    }

    public function list_players():void
    {
        for each (var p:String in m_players)
        {
            trace(p);
        }
    }
}

And from anywhere in your application, you will be able to access and use the Game class like this:

Game.instance.add_player("Samuel");
Game.instance.add_player("Julia");
Game.instance.add_player("Sheldon");

Game.instance.list_players();

In this case, new Game(), will only be called when we fetch the first instance at the first line, Game.instance.add_player("Samuel");. The code will, of course, output:

Samuel
Julia
Sheldon

And that’s pretty much it. If you would like to know more about this pattern and other patterns in general, I would strongly reccommend the “Design Patterns” book.