Advertisement

Quick Tip: The Singleton Pattern

by

Twice a month, we revisit some of our readers’ favorite posts from throughout the history of Activetuts+. This week's retro-Active Quick Tip, first published in June 2010, is an introduction to a popular (but commonly mis-used) design pattern.

In this Quick Tip we are going to talk about the Singleton design pattern and how it can help you to optimize your code when you need exactly one instance of a class.


Step 1: Introduction

As a programmer you must be aware that there are some cases where you want to use an instance of a class, but you want to create just one and keep it throughout the entire program. Well, that's what Singletons are for.


Step 2: What is a Singleton?

A Singleton is a Object-Oriented Design Pattern used by many programmers; it lets you create a sort of "global" instance of a class. It is created in such a way that only one unique instance can exist, so that all instances of that class are in exactly the same state.


Step 3: Why Would We Use it?

The most common example would be a score - for example a football score. You would have a Score class, with properties homeTeamScore and awayTeamScore and a method like increaseScore(team:Team).

Both teams must be able to increase their score when they make a goal, but you can't give each team their own Score instance; you want both to access and modify the same one.

This is a case where a Singleton is a perfect solution, since it could work as a global instance that anybody can access; you will have just one instance for everyone, so you don't have to worry that each team will be modifying a different score.


Step 4: Singleton Class

Now let's start creating a singleton in AS3, but first remember the key elements of a singleton:

  • Anyone must be able to access it.
  • Just one instance can be created.

Create a new AS3 class and call it Singleton.as.

(Not familiar with class-based coding? Check out this quick intro.)

Here's the basic Singleton code:

package  {

	public class Singleton {

		private static var instance:Singleton;		//This will be the unique instance created by the class
		private static var isOkayToCreate:Boolean=false;	//This variable will help us to determine whether the instance can be created

		public function Singleton() {
			//If we can't create an instance, throw an error so no instance is created
			if(!isOkayToCreate) throw new Error(this + " is a Singleton. Access using getInstance()");
		}

		//With this method we will create and access the instance of the method
		public static function getInstance():Singleton
		{
			//If there's no instance, create it
			if (!instance)
			{
				//Allow the creation of the instance, and after it is created, stop any more from being created
				isOkayToCreate = true;
				instance = new Singleton();
				isOkayToCreate = false;
				trace("Singleton instance created!");
			}
			return instance;
		}
	}
}

Step 5: Create a Flash Project

Now let's go and test the Singleton, first create a new Flash file named Main.fla. On the properties panel set the class also to Main.


Step 6: Create a Singleton

Create a new class named "Main" and create an instance of Singleton using the constructor:

package
{

	import flash.display.MovieClip;

	public class Main extends MovieClip
	{
		public function Main()
		{
			var testSingleton:Singleton = new Singleton();
		}
	}
}

Save and run it, you will see that it throws an error telling us to use the getInstance() function instead, so go ahead and do that:

package
{

	import flash.display.MovieClip;

	public class Main extends MovieClip
	{
		public function Main()
		{
			var testSingleton:Singleton = Singleton.getInstance();
		}
	}
}

Save and run it, there's no error now, and you can see in the console the text "Singleton instance created!", meaning that it was created successfully.

So when you use a Singleton class, you cannot use new Singleton(), you have to use Singleton.getInstance() instead.


Step 7: Add Properties to the Class

The Singleton isn't very useful at the minute. Let's add a property:

package  {

	public class Singleton {

		private static var instance:Singleton;		//This will be the unique instance created by the class
		private static var isOkayToCreate:Boolean=false;	//This variable will help us to determine whether the instance can be created

		//new example property:
		public var exampleProperty:String = "This is an example";
		
		public function Singleton() {
			//If we can't create an instance, throw an error so no instance is created
			if(!isOkayToCreate) throw new Error(this + " is a Singleton. Access using getInstance()");
		}

		//With this method we will create and access the instance of the method
		public static function getInstance():Singleton
		{
			//If there's no instance, create it
			if (!instance)
			{
				//Allow the creation of the instance, and after it is created, stop any more from being created
				isOkayToCreate = true;
				instance = new Singleton();
				isOkayToCreate = false;
				trace("Singleton instance created!");
			}
			return instance;
		}
	}
}

Now, in Main.as, you can access testSingleton.exampleProperty just as if it were a normal class. Try tracing it out.


Step 8: Try Creating Another Singleton

To prove that the Singleton does what it's supposed to do, create another singleton and change the example property of one of them:

package
{

	import flash.display.MovieClip;

	public class Main extends MovieClip
	{
		public function Main()
		{
			var testSingleton:Singleton = Singleton.getInstance();
			var anotherSingleton:Singleton = Singleton.getInstance();
			anotherSingleton.exampleProperty = "This is set in anotherSingleton";
			trace(testSingleton.exampleProperty, anotherSingleton.exampleProperty);
		}
	}
}

What do you think will happen?

This even works if you create the Singleton variables in different classes.


Conclusion

The singleton pattern can be used on any code, and I highly recommend it if you are going to use just one instance of a class since it gives you better control of it. I hope you liked this Quick Tip, thanks for reading!

Saludos -Eduardo