When should I use the Singleton NOT pattern? (Beyond the obvious)

I know well that you want to use Singleton to provide a global access point to a specific state or service. The benefits of this template need not be listed in this question.

I'm interested in situations where Singleton may seem like a good choice at the beginning, but may come back to bite you. Again and again, I saw authors in books and posters on SO saying that the Singleton template is often a very bad idea.

The Gang of Four states that you will want to use Singleton when:

  • There must be exactly one instance of the class, and it must be accessible to clients from a known access point.
  • when a single instance should be an extensible path of a subclass, and clients should be able to use an extended instance without changing their code.

These points, although certainly noteworthy, are not the practical ones that I seek.

Does anyone have a set of rules or cautions that you use to evaluate whether you are really, really sure you want to use Singleton?

+43
language-agnostic design design-patterns singleton
Nov 02 '10 at 0:26
source share
8 answers

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; } 
+63
Nov 02 '10 at 1:13
source share

One word: testing

One of the hallmarks of validation is the free connection of classes, which allows you to isolate one class and fully test it. When a single class uses a singleton (and I'm talking about a classic singleton that provides its own singularity, the static getInstance () method), the singleton and singleton users become inextricably linked. It is not possible to test a user without also testing a singleton.

Singleton is a disaster for testing. Since they are static, you cannot drown them out with a subclass. Because they are global, you cannot easily change the link they point to without recompiling or hard work. Everything that singleton uses in a magical way gets a global reference to something that is hard to control. This makes it difficult to limit the volume of the test.

+12
Nov 02 '10 at 1:02
source share

The biggest mistakes I've seen with Singleton are developing a single-user system (say, a desktop program) and using Singleton for many things (like “Settings”), and then you want to become multi-user like a website or service.

This is similar to what happened with C functions with internal static buffers when they were used in multi-threaded programs.

+6
Nov 02 2018-10-02T00:
source share

I would say avoid singleton at all costs. It limits application scaling. Actually analyze the problem you are facing and think about scalability and make decisions based on how scalable you want your application.

At the end of the day, a singleton acts as a bottleneck in a resource if it is not designed correctly.

Sometimes you introduce this bottleneck without fully understanding what the consequences of this will be in your application.

I ran into problems when working with multi-threaded applications that try to access the singleton resource but get into deadlocks. That's why I try to avoid singleton as much as possible.

If you introduce singletones into your design, make sure you understand the consequences of the execution, make some diagrams and find out where this might cause the problem.

+4
Nov 02 '10 at 0:40
source share

Singleton is often used as a trick for everything that people cannot bother to encapsulate properly in the place where it is really needed, with appropriate accessories.

The end result is tarball, which ultimately collects everything static throughout the system. How many people here NEVER saw a class called Globals in some supposedly OOD code they had to work with? Ugh.

+3
Nov 02 2018-10-10T00:
source share

I would not avoid this completely in any design. However, care must be taken regarding its use. He can become an object of God in many scenarios and, therefore, defeat the goal.

Remember that this design scheme is a solution to some problems, but not all problems. In fact, this is the same for all design patterns.

0
Nov 02 2018-10-11T00:
source share

I don’t consider myself an experienced programmer, but my current opinion is that you don’t really need Singleton ... yes, at first it seems that you work first (like globals), but then “oh my” moment comes when you need another instance.

You can always pass or enter an instance, I really do not see a situation where it would be much easier or necessary to use Singleton

Even if we reject everything, the question remains of code testability.

0
Nov 12 '10 at 21:53
source share

See the first answer in What is an Alternative to Singleton . "

-2
Nov 02 2018-10-02T00:
source share



All Articles