The Singleton Pattern ensures a class has only one instance, and provides a global point of access to it.
What is our motivation to use it? In nearly every application, there is a need to have an area from which to globally access and maintain some type of data. There are also cases in object-oriented (OO) systems where there should be only one class, or a predefined number of instances of a class, running at any given time.
For example, when a class is being used to maintain an incremental counter, the simple counter class needs to keep track of an integer value that is being used in multiple areas of an application. The class needs to be able to increment this counter as well as return the current value. For this situation, the desired class behavior would be to have exactly one instance of a class that maintains the integer and nothing more.
The basic structure is as follows, there is a good discussion here
// a lot of methods are omitted here
class Singleton
{
public:
static Singleton* getInstance( );
~Singleton( );
private:
Singleton( );
static Singleton* instance;
};
class ChocolateBoiler {
private:
static ChocolateBoiler* uniqueInstance;
bool empty;
bool boiled;
ChocolateBoiler(const ChocolateBoiler& ); // Disable copy constructor
void operator=(const ChocolateBoiler& ); // Disable assignment operator
ChocolateBoiler(){
empty = true;
boiled = false;
}
~ChocolateBoiler() {
uniqueInstance = NULL;
}
public:
static ChocolateBoiler* getInstance() {
if(uniqueInstance == NULL ) {
std::cout << "Creating unique instance of Chocolate Boiler" << std::endl;
uniqueInstance = new ChocolateBoiler();
}
std::cout << "Returning instance of Chocolate Boiler"<< std::endl;
return uniqueInstance;
}
void fill() {// fill the boiler with a milk/chocolate mixture
if(isEmpty()){
empty = false;
boiled = false;
}
}
void drain() { // drain the boiled milk and chocolate
if(!isEmpty() && isBoiled()){
empty = true;
}
}
void boil() { // bring the contents to a boil
if(!isEmpty() && !isBoiled()) {
boiled = true;
}
}
bool isEmpty() const { return empty; }
bool isBoiled() const { return boiled; }
};
The main function is
#include <iostream>
#include <./chocolatefactory.hpp>
ChocolateBoiler* ChocolateBoiler::uniqueInstance = NULL;
int main()
{
ChocolateBoiler* boiler = ChocolateBoiler::getInstance();
boiler->fill();
boiler->boil();
boiler->drain();
// will return the existing instance
ChocolateBoiler* boiler2 = ChocolateBoiler::getInstance();
if( boiler == boiler2 )
std::cout << "Got same boiler" << std::endl;
else
std::cout << "Oh oh! got a different boiler" << std::endl;
return 0;
}
The result is