Quantcast
Channel: GameDev.net
Viewing all articles
Browse latest Browse all 17825

Design Patterns: Singleton Basics

$
0
0
Design Patterns are among the bread and butter of the good developer's cookbook. Basically, any serious job interview you will have as a Junior to Mid-level programmer, will have a question on Design Patterns in it. They are very important in many regards and essential in others. But no other is quite as controversial as the Singleton Design Pattern.

Very rarely have I seen a project that has no implementation of this whatsoever. In this article, I will explain the importance of using this Design Pattern and how to implement it.

Singleton


So what is really the Singleton? Well, it is a Design Pattern that allows us to restrict the class that implements it to have just one instance of itself at all times. In plain terms this means that if we implement Singleton on a class, it will always have just one instance. That's it. That instance will be accessible throughout your code but you will no longer be able to create new instances of the class.

Why should we use it?


There are many reasons. Here is a short list of some “why we should do it” stuff:
  • You will have one singular encapsulation module for the logic of your class that will serve in a way that you can do easy dynamic changes without changing the scope of your programming logic.
  • You can manage a single resource clearly through your code.
  • As the Singleton Design Pattern implements the lazy instantiation, it allows us to get and use it's encapsulated logic as it is needed at runtime.

When do we need Singleton


An implementation of Singleton is needed on classes that would represent something that you use in one form and consistently throughout your project. That would be per say your in-game's scoreboard that monitors your current point count. It's something that you would need during your gameplay experience to increment your score. However, you would need it at the end of your level to calculate your high-score. In that regard, implementing Singleton to your scoreboard class would be perfect. You increment your score and it is stored in the single scoreboard object that you have. When the time comes for us to calculate your in-game high score, we simply access this object and see what you've accumulated.

Another classic case would be to store and access the rules of a board game. Normally, if you are developing a regular board game, your rules should be the same all together. There is absolutely no reason for you to create a new object every time and for every game you play. There is no point to have this both from a performance standpoint and from data loss perspective.

But why use Singleton and not a class with static methods?


Singleton is not a replacement for a class with static methods. It's a totally different thing. It's also used in different cases.

You would use a class with static methods in situations where you do not need an instance at all. Normally, the static methods are going to be used to do operations with objects that are outside of the class. Generally, the static methods should be implemented in a more generic way as well. They are probably going to be used by multiple logic segments with different parameters altogether. With Singleton, you have a class that should work like a normal one. That's it. Like in the examples above, it's not merely a class containing some methods that are going to be used as tools later on. It is going to contain programming logic on its own.

So to talk in examples – you will need Singleton in your board game’s rules and in your in-game scoreboard. You would need a static class if you plan to dynamically instantiate reusable UI elements that serve only temporary purpose and are not a part of your core interface.


Singleton Implementations


Here we will take a look at a real implementation of Singleton in Java.

Java class implementing Singleton:

public class Scoreboard {

	public int currentScore; //we will use this for the score later on
	private static Scoreboard singleton = null; //this we will need for the implementation
	
	protected Scoreboard(){
		//nothing here really. At least for this example.
	}

	public static Scoreboard instance(){
		//this is the method that we are going to use to return the one instance of this class.
		if(singleton == null){
			singleton = new Scoreboard();
		}
		
		return singleton;
	}

}

Now to use this implementation in another class in order for you to see how it's actually going to happen.

public class HelloScoreboard{
	public static void main(String[] args){
		Scoreboard.instance().currentScore = 10; //here we call and set currentScore
		System.out.println(Scoreboard.instance().currentScore.toString());
	}
}

As seen in the example above, we have the Singleton class Scoreboard. It has its instance() method. Through this method we will get the one instance of this class. Any calls we want to make to the class have to be done through this method. Now, if we take a look at the currentScore variable, we will see that in the main method of HelloScoreboard we are setting it to the value of 10. From this point on, every time we refer to this variable, its value is going to be 10, at least until we change it for some reason. Again, its value can be changed wherever we please.


Singleton Issues


There are some major issues with the Singleton Design Pattern to look out for. If not implemented correctly and in turn, not handled correctly, you may be getting more issues then you would wish.

Multithreading


This is quite possibly one of the biggest issues out there. The problem here is something like this - let's say that you have two threads that for some reason are calling our Singleton object. Since they are two separate threads, we would get a logical paradox - two instances of the Singleton object. That's just not what we want at all. What we want is to have one instance that encapsulates a singular resource and functionality. By having the multithread issue, we completely make the point of the Singleton useless.

How can we fix this problem ?

Well, generally this is not a problem that can be truly "fixed". It can merely be "mended". We can do that by synchronising/locking the Singleton object.

Here is a Java implementation for this:

public class Scoreboard {

	public int currentScore; //we will use this for the score later on
	private static Scoreboard singleton = null; //this we will need for the implementation
	
	protected Scoreboard(){
		//nothing here really. At least for this example.
	}

	public static Scoreboard instance(){
		//this is the method that we are going to use to return the one instance of this class.
		if(singleton == null){
            synchronized(Scoreboard.class) {
                if(singleton == null){
					singleton = new Scoreboard();
                }
            }
		}
		
		return singleton;
	}

}

So this is what basically is happening here - on entry, the first thread will check if the singleton instance is null. If it is, then we go to the synchronized lock. When the other thread enters, the creation of the instance is locked. At this point we have another failsafe as well. If/when the second thread manages to get past the lock, when the first thread is done, we have a new check. At this point we block out the issue with the multiple instances.

Unit Testing


This is another major Singleton issue. That's because we would need to test the Singleton instance with every single class that uses it in one way or another. That's just not the idea of the Unit Tests. We want to test just one thing - not one thing and the Singleton. That makes two things and it also makes a corrupt test. Another thing to note here is the fact that the Singleton object has a "state" of a sort. At any time you change something, you change the Singleton's values and thus - it's current state. That makes it near impossible to track the states and the test data in a massive test case.

Again, as with the Multithreading issue, here we cannot fix the problem and make it go away. However, there is a workaround that can be used to make things a little bit easier. What can be done is this - for the tests, we can implement an overloaded version of the instance() method that would go with our needs. This is best seen by an example, so let's get into it.

We will change up the Scoreboard class and add some additional logic to it - we will have a public double time that would be used for the time we've spent while we accumulate the score. We will also create a class that is going to call both the current score and the time. We are going to call this class EventAtScore and it is going to initiate an event when the player has reached a specific score at a specific time. That will be also the class that we are going to perform the tests on.

First off, here is the Scoreboard class:

public class Scoreboard {

	public int currentScore; //we will use this for the score later on
    public double time;
	private static Scoreboard singleton = null; //this we will need for the implementation
	
	protected Scoreboard(){
		//nothing here really. At least for this example.
	}

	public static Scoreboard instance(){
		//this is the method that we are going to use to return the one instance of this class.
		if(singleton == null){
            synchronized(Scoreboard.class) {
                if(singleton == null){
					singleton = new Scoreboard();
                }
            }
		}
		
		return singleton;
	}
    
    public static Scoreboard instance(int score, int theTime){
		//this is the method that we are going to use to return the one instance of this class.
        //this is the overloaded method that we are going to use for the tests.
		if(singleton == null){
            synchronized(Scoreboard.class) {
                if(singleton == null){
					singleton = new Scoreboard();
                    singleton.currentScore = score;
                    singleton.time = theTime;
                }
            }
		}
		
		return singleton;
	}

}

Ok, so now let's go to the EventAtScore class. This would be it's normal construction.


public class EventAtScore{

    public String eventMessage = "";
    
    public EventAtScore(String defaultMessage){
    	this.eventMessage = defaultMessage;    
    }
    
    public void displayEventMessage(){
    
        Scoreboard theBoard = Scoreboard.instance();
        
        if(theBoard.currentScore == 100 && theBoard.time == 60){
        	System.out.println(eventMessage);   
        }
    }
}


And this is what we would have if we wanted to make a specific test.


public class EventAtScore{

    public String eventMessage = "";
    
    public EventAtScore(String defaultMessage){
    	this.eventMessage = defaultMessage;    
    }
    
    public void displayEventMessage(){
    
        //Here we use the overloaded version of the instance() method
        Scoreboard theBoard = Scoreboard.instance(100, 60);
        
        if(theBoard.currentScore == 100 && theBoard.time == 60){
        	System.out.println(eventMessage);   
        }
    }
}


As seen above, here we are able to produce values in the instance on it's initialization. That suits our needs for testing, at least to some point.

There are more flexible and better ways to perform such a test, however I simply wanted to make a point with this. If you are interested in how this can be done properly, you can read up on the following materials:


Debugging and Solving Issues


Since the Singleton can be called at any one point in your code, this makes it really hard to track when your instance got it's values/logics messed up beyond expectations.

The resolution here should really be to be careful why, when and where you call your Singleton object but mostly - you need to watch out if your implementation of this pattern is really needed. If you are making too many calls to the Singleton object, you might want to consider another approach.

The Singleton "knows" Too Much


Some times, the deviation of the Sinleton pattern from the traditional OOP understanding is making it an issue of what kind of things it can manipulate. We should not put calculations or any process that has a major role in our code. That's to say that if you have some basic and driving logic, you should by all means NOT include any parts of it inside the Singleton implementation.

Dependency Issues


This is a real blocker as well. When we use the Singleton Design Pattern, we take the risk of making the code too dependent on the object's state/values/logic. Let's say we expect the Singleton object to behave in a certain fashion. We base our logic on that behavior and we think that things are going to go smooth. And it does. Everything is going ok and you are happy that your code works as expected. Well, that's up until you totally forget what you've done with this. And then you decide to make some minor changes here and there. Now, your Singleton object does not behave the way you thought it would. Not only that, now you are totally not in controll of what's happening.

Singleton Implementation in Other Languages


Java is a fairly clear language to port from, however it would be good to take a look at other implementations and how things go there as well.

Singleton in C++


This would be the basic Scoreboard Singleton example from above, only done in C++.

#include <iostream>

using namespace std;

// This is the Scoreboard
class Scoreboard {

    public:
        static Scoreboard* singleton;//The Singleton Instance
    	int currentScore;
    	double time;

    public:
        static Scoreboard* Instance();

    private:
        Scoreboard();

};

Scoreboard* Scoreboard::singleton = NULL;

Scoreboard::Scoreboard()
{
    
}

Scoreboard* Scoreboard::Instance()
{
    if ( singleton == NULL ) {
    	singleton = new Scoreboard();
    }

    return singleton;
}

Singleton in C#


This would be the basic Scoreboard Singleton example from above, only done in C#.

using System;

public class Scoreboard
{
   private static Scoreboard singleton;
    
   public int currentScore;
   public double time;

   private Scoreboard(){
   
   }

   public static Scoreboard Instance
   {
      get 
      {
         if (singleton == null)
         {
            singleton = new Scoreboard();
         }
         return singleton;
      }
   }
}

Interesting Points


I chose Java for most of the examples in the previous chapters because I find it to be really easily portable to other programming languages. If you are doing work with C++ or C# you should have no problem in porting this code. The concepts are basically all the same.

Things You Can Look Up


Here are some online materials that I've fount useful on the Singleton subject:


Conclusion


Using Design Patterns in your code is really something from which you can benefit a lot. Singleton is quite possibly the most common of them all along side with the Factory Design Pattern.

Knowing how to implement Singleton can serve you really well.

Article Update Log


14 May 2013: The article was written.
16 May 2013: Added "Things to Look Out For" in the article.
23 May 2013: Refactored the article. Added a couple of issues with the Singleton.
24 May 2013: Added materials to the article.
24 May 2013: Added more code to the Testing section of the article. Added more materials.
24 May 2013: Added basic Singleton implementations for C++ and C#.

Viewing all articles
Browse latest Browse all 17825

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>