Summary version:
Do you know how often you use global variables? Ok, now use the Singletons EVEN LESS. Actually much less. Never again. They share all the problems that global groups with covert communications face (directly affecting verifiability and maintainability), and often the “only one can exist” restriction is actually an erroneous assumption.
Detailed answer:
The most important thing to understand about one single is the global state. This is a template for displaying one instance of global unrestricted access . It has all the programming problems that global groups have, but it also accepts some interesting new implementation details and otherwise there is very little real value (or, indeed, it can come at an unnecessary extra cost with one aspect of the instance). The implementation is so different that people often mistakenly take it for an object-oriented encapsulation method when it is really just a bizarre single instance of the global one.
The only situation in which you should consider a singleton is that having more than one instance of already global data will actually be a logical or hardware access error. Even then, you usually should not directly access the singleton, but instead provide a shell interface for which allowed to create instances as many times as you need, but only to access the global state. That way, you can continue to use dependency injection , and if you can ever forget the global state from class behavior, this is not a radical change in your system.
There are subtle issues with this, however, when it seems that you are not relying on global data, but you. So (using the dependency injection of the interface that wraps the singleton) is just a suggestion, not a rule. In general, this is still better, because at least you can see that the class relies on singleton, while just using the :: instance () function inside the abdomen of a class member function hides this dependency. It also allows you to retrieve globally-based classes and do more effective unit tests for them, and you can go through mock-do-nothing objects, where if you incinerate a singleton dependency directly in the class, it's a lot more complicated.
When baking a singleton :: instance call, which also runs in a class, you make inheritance impossible . Workflows usually break a “single instance” of a singleton part. Consider a situation where you have several projects based on common code in the NetworkManager class. Even if you want this NetworkManager to be a global state and a single instance, you should be very skeptical about turning it into a singleton. By creating a simple singleton that creates an instance, you basically make it impossible for any other project to be retrieved from this class.
Many people think that ServiceLocator is an anti-template, but I believe that it is half a step better than Singleton and effectively overshadows the goal of the Go4 template. There are many ways to implement a service locator, but the main idea is that you break down the design of the object and the access of the object to two steps. Thus, at runtime, you can connect the corresponding derived service, and then access it from one global point of contact. This has the advantage of explicitly building the object, and also allows you to get from your base object. This is still bad for most of the stated reasons, but it's less bad than Singleton, and is a replacement replacement.
One specific example of an acceptable singleton (read: servicelocator) may be to bypass the c-style interface of an instance, such as SDL_mixer. One example of a single, often naively implemented where it probably shouldn't be, is in the registration class (what happens when you want to connect to the AND console to disk? Or if you want to write subsystems separately.)
However, the most important global state problems always arise when you try to implement proper unit testing (and you should try to do this). It is much more difficult to deal with your application when you try to write and read on the disk, connect to live servers and send real data, or sound from your speakers, willy-nilly, in the bowels of classes you really don't have access to. It's much, MUCH better to use dependency injection so that you can mock up the do-nothing class (and see that you need to do this in the class constructor) in case of a test plan and point to it without the need for a divine global state that your class depends on .
Related links:
Using vs Emergence template
Templates are useful as ideas and terms, but unfortunately, people seem to feel the need to “use” the template when models are actually implemented as needed. Often, a singleton is specially trained in simplicity because it is often discussed. Create your system with the awareness of patterns, but don't create your system specifically to bend them just because they exist. They are useful conceptual tools, but just as you do not use every tool in the toolbar just because you can, you should not do the same with templates. Use them as needed and no more or less.
Service Locator Single Instance Example
#include <iostream> #include <assert.h> class Service { public: static Service* Instance(){ return _instance; } static Service* Connect(){ assert(_instance == nullptr); _instance = new Service(); } virtual ~Service(){} int GetData() const{ return i; } protected: Service(){} static Service* _instance; int i = 0; }; class ServiceDerived : public Service { public: static ServiceDerived* Instance(){ return dynamic_cast<ServiceDerived*>(_instance); } static ServiceDerived* Connect(){ assert(_instance == nullptr); _instance = new ServiceDerived(); } protected: ServiceDerived(){i = 10;} }; Service* Service::_instance = nullptr; int main() { //Swap which is Connected to test it out. Service::Connect(); //ServiceDerived::Connect(); std::cout << Service::Instance()->GetData() << "\n" << ((ServiceDerived::Instance())? ServiceDerived::Instance()->GetData() :-1); return 0; }