Singleton Howto
Introduction
A Singleton is a class of which there can only be a single Object in the programm. It is described as an design-pattern in Gof:96 (the famous design-pattern book). In the molecuilder there are so far several Singletons serving a wide range of purposes:
- the World, which handles all atoms, molecules and bonds
- the ActionRegistry, which stores all created actions by name for later use
- the UIFactory, which is an AbstractFactory (another design-pattern from Gof:96) and handles all creation of gui elements to ensure a single type throughout the programm
- the logger and errorLogger classes, that can be used to output messages on the screen depending on certain conditions
Because those classes can only be instantiated once you cannot simply call new World()
or delete
on them. Rather they have to be constructed and accessed using the singleton mechanism. This mechanism consists of four static functions (and a fifth that is used internally, but we will get to that later). These functions are
Singleton& Singleton::getInstance()
: returns the instance of the singleton as a referenceSingleton* Singleton::getPointer()
: returns the instance of the singleton as a pointervoid Singleton::purgeInstance()
: destroys the single Instance of the singletonSingleton& Singleton::resetInstance()
: resets the Singleton, i.e. destroys the old instance and creates a new one
If you need the instance of the singleton it is usually fine just to use one off the accessor functions (i.e. getInstance()
or getPointer()
. Any creation of the Singleton is then handled by these functions, so that the same object will be returned whenever one of these functions is called. This easy process is true for most singletons you will need to use. The only special singleton is the UIFactory.
Special functions of the UIFactory
If you simply call the getInstance()
method of the UIFactory class the program will crash. This happens, because the UIFactory in itself is abstract and needs to know what kind of user interface it should produce later on. You need to tell the class the type of UI using the void UIFactory::makeUserInterface(InterfaceTypes type)
method. This will also take care of creating the sole instance, so that the accessor functions will work afterwards. What this also means is, that you cannot reset()
the UIFactory, because at that point it wont know anymore what to construct. A sequence of UIFactory::purgeInstance()
, UIFactory::makeUserInterface()
and UIFactory::getInstance()
will work though.
In order to make life easier and propagate changes to the singleton mechanism to all those classes, there is a simple framework class that can be used to make any other class a singleton through inheritance. This class can be found in the Pattern directory.
How to make a class Singleton
Most of the time you will only need singletons that don't require additional information for creation. So I will cover the basic case for constructing singletons first and then explain what has to be changed to make it accept special parameters. Singletons are created by inheriting from the Singleton<class T> template using the Curiously recurring template pattern (CRTP). What this means is, that the class they inherit from carries the inheriting class as a template parameter. For example:
class MySingletonExaple : public Singleton<MySingletonExample>{...}
If you want to know more about this idiom have a look at the wikipedia page for this idiom, but don't worry if you don't quite get how this works for now, for the use of the singleton framework this is not important.
If you want to make a class a singleton you can use the following sequence of steps.
- Inherit from the singleton pattern using the CRTP as above:
class MySingletonExaple : public Singleton<MySingletonExample>{ ...
} - Make constructor and destructor private to avoid creation or destruction from outside the class:
class MySingletonExaple : public Singleton<MySingletonExample>{ private: MySingletonExample(); ~MySingletonExample(); ...}
- give the inherited class access to the class internals using a friend declaration:
class MySingletonExaple : public Singleton<MySingletonExample>{ friend class Singleton<MySingletonExample>; // don't forget the template parameters here private: MySingletonExample(); ~MySingletonExample(); ...}
- include the file "Patterns/Singleton_impl.hpp" that carries the implementation details of the singleton functions in your implementation file of the class.
- make the compiler construct the template instantiations. For this you can use the defined keyword
CONSTRUCT_SINGLETON(name)
at any toplevel point in the implementation file.void MySingletonExample::foo(){...} void MySingletonExample::bar(){...} CONSTRUCT_SINGLETON(MySingletonExample) // no ; after this
Singleton with initialization parameters
Sometimes it is necessary for a singleton to be passed some initilization parameters. For example the UIFactory mentioned above needs to know what kind of user interface it has to produce. Making a singleton that takes initialization parameters is only sligtly different from the steps lined out above. Here are all the differences:
- pass an extra
false
to the template to deactivate the standard instantiation mechanism - write a method that handles the special parameters and instantiation. In this method you can use the
setInstance(T*)
method inherited from the singleton pattern to set the created instance. ThesetInstance()
method will only work when thefalse
template parameter has been set and produce errors otherwise.