Harold Serrano

View Original

How to implement a Singleton Design Pattern

Introduction

Object-Oriented Programming principles advise against the implementation of global variables. However, there are times when you need such type of variables. So, if global variables shouldn't be implemented, how can you declare a variable that will act as such?

The answer is a design pattern known as the Singleton Design Pattern.

The Singleton Design Pattern is a pattern that ensures that one and only one object is instantiated for a given class. This allows you to treat the object as a global variable (sort of).

Implementing a Singleton Design Pattern

So here is a question:

How do you prevent more than one object from being instantiated?

Let’s go through a thought process:

An instance of a class MyObject() can be created as shown in listing 1.

Listing 1.
MyObject *myObject=new MyObject();

If we want to create another instance, we follow the same procedure as in listing 1.

So, as long as is a public class, we can create as many instances as we want. But what happens if it is not a public class?

For example, what happens when you set the constructor of a class as a protected method as shown in listing 2?

Listing 2.
class SingletonPattern{

private:

protected:

    //constructor
    SingletonPattern();

public:

};

Because the constructor in listing 2 is protected, do you think that the class can be instantiated?

We can't instantiate the class. We would need to have an instance of the class to call it, but we can't have an instance because no class can instantiate it.

Now, what would happen if we add a static method as shown in listing 3.

Listing 3
class SingletonPattern{

private:

protected:

    //1. constructor
    SingletonPattern();

public:

    //2. shared instance for the singleton
    static SingletonPattern* sharedInstance();

};

and in the implementation of the method we do the following:

Listing 4
SingletonPattern* SingletonPattern::sharedInstance(){

  if (instance==0) {
  instance=new SingletonPattern();
  }

  return instance;

}

Now, do you think we can instantiate the class? We can and the way to get an instance of the object is by doing the following:

Listing 5
SingletonPattern *mySingleton=SingletonPattern::sharedInstance();

Listing 4 is interesting. The variable instance is a static variable that holds our reference of the class.

If the instance variable is null, then no singleton class has been created. And if that is the case, we instantiate the class through its protected constructor and assign a unique instance to it.

And if the instance variable is not null, it means that the singleton has been created and the instance referencing it gets returned.

The full implementation of a Singleton Design Pattern

Let's provide the full implementation of a singleton.

Listing 6. SingletonPattern.h file
class SingletonPattern{

private:

    //1. private variable

    int i;

protected:

    //2. constructor
    SingletonPattern():i(0){};

    //3. destructor
    ~SingletonPattern(){};

public:

    //4. static instance for class singleton

    static SingletonPattern* instance;

    //5. shared instance for the singleton

    static SingletonPattern* sharedInstance();

    //6. set the value of i
    void setValue(int uValue);

    //7. get the value of i
    int getValue();
};

Listing 6 shows the full implementation of the singleton class. Line 2 shows the protected constructor. Line 4 shows the static variable called instance. Line 5 shows the sharedInstance() method that is called every time you instantiate the singleton.

Listing 7. SingletonPattern.c file
#include "SingletonPattern.h"
SingletonPattern* SingletonPattern::instance=0;

SingletonPattern* SingletonPattern::sharedInstance(){

    if (instance==0) {
        instance=new SingletonPattern();
    }

    return instance;

}

void SingletonPattern::setValue(int uValue){

    i=uValue;
}

int SingletonPattern::getValue(){
    return i;
}

The implementation file shows the sharedInstance() method. In this method, the static variable instance is checked.

Now, here is the beauty of this design pattern. In our example, the singleton class contains a variable called i. You can set the value of this variable anywhere in your code by doing what is shown in listing 8.

Listing 8. Setting the value of i
SingletonPattern *singleton=SingletonPattern::sharedInstance();

singleton->setValue(5);

If you want to read this value somewhere else in your code, you do the following:

Listing 9. Reading the value of i
SingletonPattern *singleton=SingletonPattern::sharedInstance();

int myValue=singleton->getValue();

The singleton class will make sure that the value of its member i is always 5 anywhere in your code. It acts as a global variable.

Of course, you can always change the value of i whenever you see it fit.

The Singleton Design Pattern is a very powerful pattern. It deserves an important place in your programming toolbox. If you want to learn more about it, you may want to read Head First-Design Patterns

Questions?

So, do you have any questions? Is there something you need me to clarify? Did this post help you? Please let me know. Add a comment below and subscribe to receive our latest game development projects.