Featured Blog | This community-written post highlights the best of what the game industry has to offer. Read more like it on the Game Developer Blogs or learn how to Submit Your Own Blog Post
OOPsie Patterns: The Singleton Pattern
Our first foray into design patterns begins with the singleton pattern, a common pattern in the creational pattern group.
Pattern Name: Singleton pattern
Type: Creational
The singleton pattern is one of the most common, basic patterns and provides a great introduction to both the creational design patterns as well as design patterns in general. However, it is also one of the more debatable patterns based on certain aspects of decoupled code (which we will discuss).
The Pattern
The singleton pattern typically applies directly to a class and is used to ensure that only one instance of that class exists throughout the entire project. Let's look at an example before we go any deeper:
Asteroids
The above is a screen shot from the classic game Asteroids by Atari. In the shot you can see several asteroids of differing sizes, the player ship (represented by the triangle near the center), and an alien ship in the upper left corner.
Now, obviously each asteroid, big or small, is an instance of some Asteroid class and since there are multiple of them, we know they can't be singletons (since there are more than one of them). To explain a singleton, let's think back to a few OOPsie's ago where we discussed polymorphism.
When we learned polymorphism we used an example of zombies and had the following code in our main function:
public class DeadRisingGame
{
static void Main(string[] args)
{
List zombies = new List()
//Create 3 new zombies
zombies.Add(new PlaidZombie());
zombies.Add(new WomanZombie());
zombies.Add(new BrownShirtZombie());
//Print some statements
foreach(Zombie zomb in zombies)
{
Console.WriteLine("Type: " + zomb.ZombieType);
Console.WriteLine("Movement Type: " + zomb.MovementType());
}
}
}
OUTPUT:
Type: Plaid-Zombie
Movement Type: Walk slowly
Type: Woman-Zombie
Movement Type: Stumble around
Type: Brown-Shirt-Zombie
Movement Type: Yell and run
Notice the bolded portion which creates a list of zombie objects and adds the zombies. Obviously, it doesn't make sense at this point to have multiple lists to which we add zombies so the list itself can be modelled with the singleton pattern. However, in the above code there is no restriction saying that we can't have another list of zombies. Let's introduct a simple singleton pattern into this example and go over the code:
public sealed class GameZombies
{
// Singleton instance
private static GameZombies _gameZombies;
// Privately stored list of all zombies
private List() _zombies;
// Public property to access zombie list
public List() Zombies { get { return _zombies; } }
private GameZombies()
{
}
// Public property to get the single instance of this class
public GameZombies Instance
{
get {
if (_gameZombies == null) {
_gameZombies = new GameZombies();
}
return _gameZombies;
};
}
// Adds a new zombie to the list of game zombies
public void Add(Zombie zomb)
{
_zombies.Add(zomb);
}
}
public class DeadRisingGame
{
static void Main(string[] args)
{
//Create 3 new zombies
GameZombies.Instance.Add(new PlaidZombie());
GameZombies.Instance.Add(new WomanZombie());
GameZombies.Instance.Add(new BrownShirtZombie());
//Print some statements
foreach(Zombie zomb in GameZombies.Instance.Zombies)
{
Console.WriteLine("Type: " + zomb.ZombieType);
Console.WriteLine("Movement Type: " + zomb.MovementType());
}
}
}
OUTPUT:
Type: Plaid-Zombie
Movement Type: Walk slowly
Type: Woman-Zombie
Movement Type: Stumble around
Type: Brown-Shirt-Zombie
Movement Type: Yell and run
Word of Warning: First thing you should immediately notice, this pattern has added quite a bit of complexity to our program. We essentially expanded a single line (which created a new list) and built a whole class around it. Like I mentioned in the intro to OOPsie Patterns, design patterns don't always need to be used and used incorrectly can create unneeded complexity.
Let's get into the pattern. At this point let's focus on the GameZombies class which is defined pretty much like a standard class however using it is quite different from anything we've seen. Notice the constructor (GameZombies) is private, meaning that function can only be accessed withing the scope of that class. Prior to this, we've always relied on creating new objects by invoking the constructor, (such as when we call new WomanZombie()) however now this is impossible. We are able to create and ensure only one instance is created by the public Instance property.
Instance is simple, return an instance of this class. To ensure we only have one instance, we store it in a static variable once it is created and constantly check that whenever we call that property. After the first time we call it, Instance will always return the same instance (get the naming convention?) of the GameZombies class. Therefore, since Instance is public and static, the GameZombies.Instance can be called throughout your project (more on this later).
Quick Note: One thing you should notice above is the sealed keyword in the class definition. This simply tells the compiler that nothing can inherit from this class (thus guaranteeing our singleton).
A Problem with Concurrency
One big drawback to the singleton pattern that needs to be fixed when implementing this pattern is the fact that concurrent code can unintentionally lock up our program! How is this possible?!
First, imagine we create two threads (lets call them ThreadA and ThreadB) and in each we try to add a different zombie through GameZombies.Instance.Add(). Concurrently, ThreadA and ThreadB both run through the Instance and ThreadA has a very miniscule lead and calls Instance a hundreth of a millisecond earlier. The computer locks the variable resource as it begins to create a new instance of GameZombies to set into our private _gameZombies variable. While this is happening ThreadB catches up and grabs _gameZombies and locks it. Suddenly both threads are thrown into what is known as deadlock, where two threads hold resources the other thread needs and both sit waiting for the other to complete (kind of like an infinite loop with threads pointing back and forth). Typically deadlocks result in the application freezing and thus are very very bad!
Thankfully C# (and other languages) provide ways around this. The above example will be modified to be:
public sealed class GameZombies
{
// Singleton instance
private static volatile GameZombies _gameZombies;
// Private object to prevent dead lock
private static object syncRoot = new Object();
// Privately stored list of all zombies
private List() _zombies;
// Public property to access zombie list
public List() Zombies { get { return _zombies; } }
private GameZombies()
{
}
// Public property to get the single instance of this class
public GameZombies Instance
{
get {
if (_gameZombies == null) {
lock (syncRoot) {
if (_gameZombies == null) {
_gameZombies = new GameZombies();
}
}
}
return _gameZombies;
};
}
// Adds a new zombie to the list of game zombies
public void Add(Zombie zomb)
{
_zombies.Add(zomb);
}
}
public class DeadRisingGame
{
static void Main(string[] args)
{
//Create 3 new zombies
GameZombies.Instance.Add(new PlaidZombie());
GameZombies.Instance.Add(new WomanZombie());
GameZombies.Instance.Add(new BrownShirtZombie());
//Print some statements
foreach(Zombie zomb in GameZombies.Instance.Zombies)
{
Console.WriteLine("Type: " + zomb.ZombieType);
Console.WriteLine("Movement Type: " + zomb.MovementType());
}
}
}
OUTPUT:
Type: Plaid-Zombie
Movement Type: Walk slowly
Type: Woman-Zombie
Movement Type: Stumble around
Type: Brown-Shirt-Zombie
Movement Type: Yell and run
First look at the change to make the _gameZombies variable volatile. In C#, volatile simply means that variable is assigned to before it can be accessed. Lock creates what we call a critical section which is a section of code that only allows one thread to run at a time. These two changes make our singleton thread-safe.
The Argument Against Singletons
Singletons should seem incredibly useful, these awesome classes that we can invoke to only have a single instance of and have access to it all over the place. What could anyone possibly dislike about them?
I mentioned it above and I'll say it again: you have access to it all over the place. Boiled down to it's most simple form, the singleton is a global variable. And as just about every programmer gets slapped on the hands and told, 'Global variables are bad!' The argument against global variables is due to them creating tightly coupled classes and code.
For instance, lets go back to the screenshot above of the classic Asteroids. If each Asteroid called ClassA.Instance, and each ship called ClassB.Instance, and the alien ships called ClassA.Instance (similar to the Asteroid) we've suddenly got all these dependencies stretching across our project. Classes should be clean, compact, and decoupled from other classes (or stand-alone). In effect, a class should need nothing but itself to be used. This idea of decoupling could warrant it's own massive blog post.
But in my opinion, global variables get a bad rap (or at least worse than whats deserved). Recently while developing RhinoXNA (a game development library), I found numerous classes where I needed to access the same variables that were stored in an object the user was required to initialize in order to use the library. What I was forced to do was place an extra item in the constructor that took that object. Eventually, I had probably 10+ classes requiring this variable. Sure the classes were decoupled, but the code seemed needlessly redundant when considering the singleton pattern.
All I needed to do was make the object a singleton to give it global static access. Part of my requirements were that the user could only 'create' one of these objects and was forced to use it. By removing the argument I was introducing a dependency across my library to this sort of adapter the user was required to use before using any other piece of the library. This ended up being a sensible use for a singleton pattern even though it was certainly possible the other way.
I think my point is that you shouldn't give singletons the cold shoulder because some people like them and some people don't. The fact is they have practical applications. Both sides of the argument are correct, there are pros and cons when using singletons, the key is in how you implement it.
The Creational Relationship
This may already be apparent, but as mentioned above, the singleton is part of the creational group of design patterns. I just want to reiterate something I mentioned in the introduction to this series. The creational patterns control the creation on objects.
It should be pretty obvious how the singleton does this, by hiding the constructor (thus controlling the creation of that object) and ensuring one instance of a class.
Conclusion
There we are, one design pattern complete! The singleton pattern is a greatly useful solution to a common problem: How do I ensure only one instance of a given class is created/used?
We've seen a simple implementation of a singleton, and how concurrency forced us to modify the provided code. And we finished up by analyzing the arguments against singletons as well as the pattern's relationship to it's design pattern group.
All in all we went through some pretty deep stuff and you probably will need to re-read this and search for other information regarding the singleton pattern especially if you weren't already familiar with this pattern. Keep learning and eventually using this pattern (in the right context!) will be second nature.
Read more about:
Featured BlogsAbout the Author
You May Also Like