What is it?
Why should you use it?
When you need an object that meets the above criteria i.e. it needs to be globally accessible and have only one instance available at any one time. A debug log hidden behind preprocessor directives is a good example. This provides the ability to output debug information to any class that requires it but it is not shipped with your final game/product.
Additional benefits include:
- As it can be lazy initialised, an instance of the object is not created if no one requests it. This saves memory and processing time (great for games!).
- Unlike a static class, a singleton has access to data only known once the program is running (e.g. any variables that need to be loaded/initialised, any data loaded from file etc.) as it is initialised at runtime.
Why shouldn’t you use it?
- Lazy initialisation, while having some possible benefit, can also prove problematic for performance. If you initialise a heavy duty object at an inopportune time a noticeable dip in performance can occur. Definitely not ideal! A Boolean flag is included in this implementation, which can be toggled depending on your performance needs.
- They violate the single responsibility principle as they control their own creation, destruction and access.
- Each class accessing the singleton calls the class directly, causing tight coupling. A nightmare for a flexible codebase.
- Singletons can cause headaches when it comes to unit testing. Unit tests are independent and the tight coupling of a singleton can cause problems. Also as singletons maintain their state each run you have to be careful of the order in which you run your unit tests (which should definitely not be the case!).
- Maintaining global state not only effects tests but can also cause problems when it comes to concurrency. Locks will need to be placed to stop race conditions, slowing down execution and increasing complexity.
Be careful when using a singleton, as they are generally overused and often not the right solution to a problem.