Pregunta

El patrón singleton es un miembro totalmente pagado del GoF 's libro de patrones , pero últimamente parece bastante huérfano por el mundo de los desarrolladores. Todavía uso bastantes singletons, especialmente para clases de fábrica , y aunque tienes que ser un Un poco cuidadoso con los problemas de subprocesos múltiples (como cualquier clase en realidad), no veo por qué son tan terribles.

Stack Overflow parece suponer especialmente que todos están de acuerdo en que los Singleton son malvados. ¿Por qué?

Por favor, respalde sus respuestas con " hechos, referencias o experiencia específica "

¿Fue útil?

Solución

Parafraseado de Brian Button:

  1. Generalmente se usan como una instancia global, ¿por qué es tan malo? Porque oculta las dependencias de su aplicación en su código, en lugar de exponerlas a través de las interfaces. Hacer algo global para evitar pasarlo es un código olor .

  2. Violan el principio de responsabilidad única : en virtud del hecho de que controlan su propia creación y ciclo de vida.

  3. Inherentemente causan que el código esté estrechamente acoplado . Esto hace que fingirlos bajo prueba sea bastante difícil en muchos casos.

  4. Llevan el estado durante toda la vida de la aplicación. Otro éxito para las pruebas, ya que puede terminar con una situación en la que las pruebas deben ordenarse, lo cual es un gran no para las pruebas unitarias. ¿Por qué? Porque cada prueba unitaria debe ser independiente de la otra.

Otros consejos

Los Singletons resuelven un problema (y solo uno).

Contención de recursos.

Si tiene algún recurso que

( 1 ) solo puede tener una instancia, y

( 2 ) necesitas administrar esa instancia única,

necesitas un singleton .

No hay muchos ejemplos. Un archivo de registro es el grande. No desea simplemente abandonar un solo archivo de registro. Desea vaciar, sincronizar y cerrarlo correctamente. Este es un ejemplo de un único recurso compartido que se debe administrar.

Es raro que necesites un singleton. La razón por la que son malos es que se sienten como global y están completamente pagados miembro del libro GoF Design Patterns .

Cuando crees que necesitas un global, probablemente estés cometiendo un terrible error de diseño.

Algunos snobs de codificación los miran como un global glorificado. De la misma manera que muchas personas odian la declaración de goto , hay otras que odian la idea de utilizar un global . He visto a varios desarrolladores hacer todo lo posible para evitar un global porque consideraron usar uno como una admisión de fracaso. Extraño pero cierto.

En la práctica, el patrón Singleton es solo una técnica de programación que es una parte útil de su conjunto de herramientas de conceptos. De vez en cuando puede encontrar que es la solución ideal y así utilizarla. Pero usarlo solo para que pueda presumir de usar un patrón de diseño es tan estúpido como negarse a usarlo porque es solo un global .

Misko Hevery, de Google, tiene algunos artículos interesantes sobre exactamente este tema ...

Los Singletons son mentirosos patológicos tiene una unidad Ejemplo de prueba que ilustra cómo Singletons puede hacer que sea difícil descubrir las cadenas de dependencia y comenzar o probar una aplicación. Es un ejemplo bastante extremo de abuso, pero el punto que hace es todavía válido:

  

Los singletons no son más que un estado global. El estado global hace que sus objetos puedan apoderarse secretamente de cosas que no están declaradas en sus API y, como resultado, Singletons convierte sus API en mentirosos patológicos.

¿Dónde se han ido todos los Singletons señala que la inyección de dependencia ha facilitado la obtención de instancias para los constructores que los requieren, lo que alivia la necesidad subyacente detrás de los Singletons globales y malos denunciados en el primer artículo.

Creo que la confusión se debe al hecho de que las personas no conocen la aplicación real del patrón Singleton. No puedo enfatizar esto lo suficiente. Singleton es no un patrón para envolver globales. El patrón Singleton solo debe usarse para garantizar que una y solo una instancia de una clase dada existe durante el tiempo de ejecución.

La gente piensa que Singleton es malo porque lo están utilizando para los globales. Es debido a esta confusión que Singleton es despreciable. Por favor, no confunda Singletons y Globales. Si se usa para el propósito para el que fue diseñada, obtendrá beneficios extremos del patrón Singleton.

Una cosa bastante mala acerca de los singletons es que no puedes extenderlos muy fácilmente. Básicamente, debe crear algún tipo de patrón de decoración o algo así si desea cambiar su comportamiento. Además, si un día desea tener varias formas de hacer eso, puede ser bastante difícil cambiarlo, dependiendo de cómo diseñe su código.

Una cosa a tener en cuenta, si USTED usa singletons, intente pasárselos a quien los necesite en lugar de hacer que accedan directamente ... De lo contrario, si alguna vez elige tener múltiples formas de hacer lo que hace singletons, será bastante difícil cambiar ya que cada clase incorpora una dependencia si accede directamente al singleton.

Entonces, básicamente:

public MyConstructor(Singleton singleton) {
    this.singleton = singleton;
}

en lugar de:

public MyConstructor() {
    this.singleton = Singleton.getInstance();
}

Creo que este tipo de patrón se llama inyección de dependencia y generalmente se considera algo bueno.

Sin embargo, como cualquier patrón ... Piénselo y considere si su uso en la situación dada es inapropiado o no ... Las reglas están hechas para romperse generalmente, y patrones no se deben aplicar de manera involuntaria sin pensarlo.

El patrón de singleton no es un problema en sí mismo. El problema es que las personas que desarrollan software con herramientas orientadas a objetos a menudo utilizan el patrón sin tener una comprensión sólida de los conceptos de OO. Cuando los singletons se introducen en este contexto, tienden a convertirse en clases inmanejables que contienen métodos auxiliares para cada pequeño uso.

Los Singletons también son un problema desde una perspectiva de prueba. Tienden a dificultar la escritura de pruebas unitarias aisladas. Inversión de control (IoC) y inyección de dependencia son patrones destinados a superar este problema de una manera orientada a objetos que se presta a pruebas unitarias .

En un recolección de basura los singletons de entorno pueden convertirse rápidamente en un problema con respecto a gestión de memoria.

También existe el escenario de subprocesos múltiples donde los singletons pueden convertirse en un cuello de botella, así como un problema de sincronización.

Un singleton se implementa utilizando un método estático. Las personas que realizan pruebas unitarias evitan los métodos estáticos porque no pueden ser burlados o golpeados. La mayoría de las personas en este sitio son grandes defensores de las pruebas unitarias. La convención generalmente más aceptada para evitarlos es usar el patrón inversión de control .

Los Singletons también son malos cuando se trata de agrupación en clúster . Porque entonces, no tienes " exactamente un singleton " en tu aplicación más.

Considere la siguiente situación: como desarrollador, debe crear una aplicación web que acceda a una base de datos. Para garantizar que las llamadas simultáneas a la base de datos no entren en conflicto, cree un SingletonDao :

para guardar hilos
public class SingletonDao {
    // songleton's static variable and getInstance() method etc. omitted
    public void writeXYZ(...){
        synchronized(...){
            // some database writing operations...
        }
    }
}

Por lo tanto, está seguro de que solo existe un singleton en su aplicación y que todas las bases de datos pasan por este y solo SingletonDao . Su entorno de producción ahora se ve así: Singleton individual

Todo está bien hasta ahora.

Ahora, considere que desea configurar varias instancias de su aplicación web en un clúster. Ahora, de repente tienes algo como esto:

Muchos singletons

Eso suena extraño, pero ahora tiene muchos singletons en su aplicación . Y eso es exactamente lo que un singleton no debe ser: tener muchos objetos de él. Esto es especialmente malo si, como se muestra en este ejemplo, desea realizar llamadas sincronizadas a una base de datos.

Por supuesto, este es un ejemplo de un mal uso de un singleton. Pero el mensaje de este ejemplo es: No puede confiar en que haya exactamente una instancia de un singleton en su aplicación, especialmente cuando se trata de agrupación.

  1. Se usa (ab) fácilmente como una variable global.
  2. Las clases que dependen de singletons son relativamente más difíciles de probar en forma aislada.

Monopoly is the devil and singletons with non-readonly/mutable state are the 'real' problem...

After reading Singletons are Pathological Liars as suggested in jason's answer I came across this little tidbit that provides the best presented example of how singletons are often misused.

Global is bad because:

  • a. It causes namespace conflict
  • b. It exposes the state in a unwarranted fashion

When it comes to Singletons

  • a. The explicit OO way of calling them, prevents the conflicts, so point a. is not an issue
  • b. Singletons without state are (like factories) are not a problem. Singletons with state can again fall in two categories, those which are immutable or write once and read many (config/property files). These are not bad. Mutable Singletons, which are kind of reference holders are the ones which you are speaking of.

In the last statement he's referring to the blog's concept of 'singletons are liars'.

How does this apply to Monopoly?

To start a game of monopoly, first:

  • we establish the rules first so everybody is on the same page
  • everybody is given an equal start at the beginning of the game
  • only one set of rules is presented to avoid confusion
  • the rules aren't allowed to change throughout the game

Now, for anybody who hasn't really played monopoly, these standards are ideal at best. A defeat in monopoly is hard to swallow because, monopoly is about money, if you lose you have to painstakingly watch the rest of the players finish the game, and losses are usually swift and crushing. So, the rules usually get twisted at some point to serve the self-interest of some of the players at the expense of the others.

So you're playing monopoly with friends Bob, Joe, and Ed. You're swiftly building your empire and consuming market share at an exponential rate. Your opponents are weakening and you start to smell blood (figuratively). Your buddy Bob put all of his money into gridlocking as many low-value properties as possible but his isn't receiving a high return on investment the way he expected. Bob, as a stroke of bad luck, lands on your Boardwalk and is excised from the game.

Now the game goes from friendly dice-rolling to serious business. Bob has been made the example of failure and Joe and Ed don't want to end up like 'that guy'. So, being the leading player you, all of a sudden, become the enemy. Joe and Ed start practicing under-the-table trades, behind-the-back money injections, undervalued house-swapping and generally anything to weaken you as a player until one of them rises to the top.

Then, instead of one of them winning, the process starts all over. All of a sudden, a finite set of rules becomes a moving target and the game degenerates into the type of social interactions that would make up the foundation of every high-rated reality TV show since Survivor. Why, because the rules are changing and there's no consensus on how/why/what they're supposed to represent, and more importantly, there's no one person making the decisions. Every player in the game, at that point, is making his/her own rules and chaos ensues until two of the players are too tired to keep up the charade and slowly give up.

So, if a rulebook for a game accurately represented a singleton, the monopoly rulebook would be an example of abuse.

How does this apply to programming?

Aside from all of the obvious thread-safety and synchronization issues that mutable singletons present... If you have one set of data, that is capable of being read/manipulated by multiple different sources concurrently and exists during the lifetime of the application execution, it's probably a good time to step back and ask "am I using the right type of data structure here".

Personally, I have seen a programmer abuse a singleton by using it as some sort of twisted cross-thread database store within an application. Having worked on the code directly, I can attest that it was a slow (because of all the thread locks needed to make it thread-safe) and a nightmare to work on (because of the unpredictable/intermittent nature of synchronization bugs), and nearly impossible to test under 'production' conditions. Sure, a system could have been developed using polling/signaling to overcome some of the performance issues but that wouldn't solve the issues with testing and, why bother when a 'real' database can already accomplish the same functionality in a much more robust/scalable manner.

A Singleton is only an option if you need what a singleton provides. A write-one read-only instance of an object. That same rule should cascade to the object's properties/members as well.

Singleton is not about single instance!

Unlike other answers I don't want to talk about what is wrong with Singletons but to show you how powerful and awesome they are when used right!

  • Problem: Singleton can be a challenge in multi-threading environment
    Solution: Use a single threaded bootstrap process to initialize all the dependencies of your singleton.
  • Problem: It is hard to mock singletons.
    Solution: Use method Factory pattern for mocking
    MyModel myModel = Factory.inject(MyModel.class); You can map MyModel to TestMyModel class that inherits it, everywhere when MyModel will be injected you will get TestMyModel instread.
  • Problem: Singletons can cause memory leeks as they never disposed.
    Solution: Well, dispose them! Implement a callback in your app to properly dispose a singletons, you should remove any data linked to them and finally: remove them from the Factory.

As I stated at the title singleton are not about single instance.

  • Singletons improves readability: You can look at your class and see what singleton it injected to figure out what is it's dependencies.
  • Singletons improves maintenance: Once you removed a dependency from a class you just deleted some singleton injection, you don't need to go and edit a big link of other classes that just moved your dependency around(This is smelly code for me @Jim Burger)
  • Singletons improves memory and performance: When some thing happens in your application, and it takes a long chain of callbacks to deliver, you are wasting memory and performance, by using Singleton you are cutting the middle man, and improve your performance and memory usage(by avoiding unnecessary local variables allocations).

My answer on how Singletons are bad is always, "they are hard to do right". Many of the foundational components of languages are singletons (classes, functions, namespaces and even operators), as are components in other aspects of computing (localhost, default route, virtual filesystem, etc.), and it is not by accident. While they cause trouble and frustration from time to time, they also can make a lot of things work a LOT better.

The two biggest screw ups I see are: treating it like a global & failing to define the Singleton closure.

Everyone talks about Singleton's as globals, because they basically are. However, much (sadly, not all) of the badness in a global comes not intrinsically from being global, but how you use it. Same goes for Singletons. Actually more so as "single instance" really doesn't need to mean "globally accessible". It is more a natural byproduct, and given all the bad that we know comes from it, we shouldn't be in such a hurry to exploit global accessibility. Once programmers see a Singleton they seem to always access it directly through its instance method. Instead, you should navigate to it just like you would any other object. Most code shouldn't even be aware it is dealing with a Singleton (loose coupling, right?). If only a small bit of code accesses the object like it is a global, a lot of harm is undone. I recommend enforcing it by restricting access to the instance function.

The Singleton context is also really important. The defining characteristic of a Singleton is that there is "only one", but the truth is it is "only one" within some kind of context/namespace. They are usually one of: one per thread, process, IP address or cluster, but can also be one per processor, machine, language namespace/class loader/whatever, subnet, Internet, etc.

The other, less common, mistake is to ignore the Singleton lifestyle. Just because there is only one doesn't mean a Singleton is some omnipotent "always was and always will be", nor is it generally desirable (objects without a begin and end violate all kinds of useful assumptions in code, and should be employed only in the most desperate of circumstances.

If you avoid those mistakes, Singletons can still be a PITA, bit it is ready to see a lot of the worst problems are significantly mitigated. Imagine a Java Singleton, that is explicitly defined as once per classloader (which means it needs a thread safety policy), with defined creation and destruction methods and a life cycle that dictates when and how they get invoked, and whose "instance" method has package protection so it is generally accessed through other, non-global objects. Still a potential source of trouble, but certainly much less trouble.

Sadly, rather than teaching good examples of how to do Singletons. We teach bad examples, let programmers run off using them for a while, and then tell them they are a bad design pattern.

See Wikipedia Singleton_pattern

It is also considered an anti-pattern by some people, who feel that it is overly used, introducing unnecessary limitations in situations where a sole instance of a class is not actually required.[1][2][3][4]

References (only relevant references from the article)

  1. ^ Alex Miller. Patterns I hate #1: Singleton, July 2007
  2. ^ Scott Densmore. Why singletons are evil, May 2004
  3. ^ Steve Yegge. Singletons considered stupid, September 2004
  4. ^ J.B. Rainsberger, IBM. Use your singletons wisely, July 2001

It's not that singletons themselves are bad but the GoF design pattern is. The only really argument that is valid is that the GoF design pattern doesn't lend itself in regards to testing, especially if tests are run in parallel.

Using a single instance of an class is a valid construct as long as you apply the following means in code:

  1. Make sure the class that will be used as a singleton implements an interface. This allows stubs or mocks to be implemented using the same interface

  2. Make sure that the Singleton is thread-safe. That's a given.

  3. The singleton should be simple in nature and not overly complicated.

  4. During the runtime of you application, where singletons need to be passed to a given object, use a class factory that builds that object and have the class factory pass the singleton instance to the class that needs it.

  5. During testing and to ensure deterministic behavior, create the singleton class as separate instance as either the actual class itself or a stub/mock that implements its behavior and pass it as is to the class that requires it. Don't use the class factor that creates that object under test that needs the singleton during test as it will pass the single global instance of it, which defeats the purpose.

We've used Singletons in our solutions with a great deal of success that are testable ensuring deterministic behavior in parallel test run streams.

Vince Huston has these criteria, which seem reasonable to me:

Singleton should be considered only if all three of the following criteria are satisfied:

  • Ownership of the single instance cannot be reasonably assigned
  • Lazy initialization is desirable
  • Global access is not otherwise provided for

If ownership of the single instance, when and how initialization occurs, and global access are not issues, Singleton is not sufficiently interesting.

I'd like to address the 4 points in the accepted answer, hopefully someone can explain why I'm wrong.

  1. Why is hiding dependencies in your code bad? There are already dozens of hidden dependencies (C runtime calls, OS API calls, global function calls), and singleton dependencies are easy to find (search for instance()).

    "Making something global to avoid passing it around is a code smell." Why isn't passing something around to avoid making it a singleton a code smell?

    If you're passing an object through 10 functions in a call stack just to avoid a singleton, is that so great?

  2. Single Responsibility Principle: I think this is a bit vague and depends on your definition of responsibility. A relevant question would be, why does adding this specific "responsibility" to a class matter?

  3. Why does passing an object to a class make it more tightly coupled than using that object as a singleton from within the class?

  4. Why does it change how long the state lasts? Singletons can be created or destroyed manually, so the control is still there, and you can make the lifetime the same as a non-singleton object's lifetime would be.

Regarding unit tests:

  • not all classes need to be unit tested
  • not all classes that need to be unit tested need to change the implementation of the singleton
  • if they do need be unit tested and do need to change the implementation, it's easy to change a class from using a singleton to having the singleton passed to it via dependency injection.

I'm not going to comment on the good/evil argument, but I haven't used them since Spring came along. Using dependency injection has pretty much removed my requirements for singleton, servicelocators and factories. I find this a much more productive and clean environment, at least for the type of work I do (Java-based web applications).

There is nothing inherently wrong with the pattern, assuming it is being used for some aspect of your model which is truly single.

I believe the backlash is due to its overuse which, in turn, is due to the fact that it's the easiest pattern to understand and implement.

Singletons are bad from a purist point of view.

From a pratical point of view, a singleton is a trade-off developing time vs complexity.

If you know your application won't change that much they are pretty OK to go with. Just know that you may need to refactor things up if your requirements change in an unexpected way (which is pretty OK in most cases).

Singletons sometimes also complicate unit testing.

Singleton is a pattern and can be used or abused just like any other tool.

The bad part of a singleton is generally the user (or should I say the inappropriate use of a singleton for things it is not designed to do). The biggest offender is using a singleton as a fake global variable.

When you write code using singletons, say, a logger or a database connection, and afterwards you discover you need more than one log or more than one database, you’re in trouble.

Singletons make it very hard to move from them to regular objects.

Also, it’s too easy to write a non-thread-safe singleton.

Rather than using singletons, you should pass all the needed utility objects from function to function. That can be simplified if you wrap all them into a helper object, like this:

void some_class::some_function(parameters, service_provider& srv)
{
    srv.get<error_logger>().log("Hi there!");
    this->another_function(some_other_parameters, srv);
}

The problems with singletons is the issue of increased scope and therefore coupling. There is no denying that there are some of situations where you do need access to a single instance, and it can be accomplished other ways.

I now prefer to design around an inversion of control (IoC) container and allow the the lifetimes to be controlled by the container. This gives you the benefit of the classes that depend on the instance to be unaware of the fact that there is a single instance. The lifetime of the singleton can be changed in the future. Once such example I encountered recently was an easy adjustment from single threaded to multi-threaded.

FWIW, if it a PIA when you try to unit test it then it's going to PIA when you try to debug, bug fix or enhance it.

Recent article on this subject by Chris Reath at Coding Without Comments.

Note: Coding Without Comments is no longer valid. However, The article being linked to has been cloned by another user.

http://geekswithblogs.net/AngelEyes/archive/2013/09/08/singleton-i-love-you-but-youre-bringing-me-down-re-uploaded.aspx

Here is one more thing about singletons which nobody said yet.

In most cases "singletonity" is a detail of implementation for some class rather than characteristic of its interface. Inversion of Control Container may hide this characteristic from class users; you just need to mark your class as a singleton (with @Singleton annotation in Java for example) and that's it; IoCC will do the rest. You don't need to provide global access to your singleton instance because the access is already managed by IoCC. Thus there is nothing wrong with IoC Singletons.

GoF Singletons in opposite to IoC Singletons are supposed to expose "singletonity" in the interface through getInstance() method, and so that they suffer from everything said above.

Singletons are NOT bad. It's only bad when you make something globally unique that isn't globally unique.

However, there are "application scope services" (think about a messaging system that makes components interact) - this CALLS for a singleton, a "MessageQueue" - class that has a method "SendMessage(...)".

You can then do the following from all over the place:

MessageQueue.Current.SendMessage(new MailArrivedMessage(...));

And, of course, do:

MessageQueue.Current.RegisterReceiver(this);

in classes that implement IMessageReceiver.

Too many people put objects which are not thread safe in a singleton pattern. I've seen examples of a DataContext (LINQ to SQL) done in a singleton pattern, despite the fact that the DataContext is not thread safe and is purely a unit-of-work object.

Because they are basically object oriented global variables, you can usually design your classes in such a way so that you don't need them.

A pattern emerges when several people (or teams) arrives at similar or identical solutions. A lot of people still use singletons in their original form or using factory templates (good discussion in Alexandrescu's Modern C++ Design). Concurrency and difficulty in managing the lifetime of the object are the main obstacles, with the former easily managed as you suggest.

Like all choices, Singleton has its fair share of ups and downs. I think they can be used in moderation, especially for objects that survive the application life span. The fact that they resemble (and probably are) globals have presumably set off the purists.

Firstly a class and its collaborators should firstly perform their intended purpose rather than focusing on deoendents. Lifecycle management (when instances are creared snd when they go out of scope) should not be part of the cladses responsibility. The accepted best practice for this is to craft or configure a new component to manage dependencies using dependency injection.

Often software gets more complicated it makes sense to have multiple independent instances of the "singleton" class with different state. Committing code to simply grab the singleton is wrong in such cases. Using Singleton.getInstance() might be ok for small simple systems but it doesn't work / scale when one might need a different instance of the same class.

No class should be thought of as a singleton but rather that should be an aplication of it's usage or how it is used to configure dependents. For a quick and nasty this does not matter- just luke hardcoding say file paths does not matter but for bigger applications such dependencies need to be factored out and managed in more appropriate way using DI.

The problems that singleton cause in testing is a symptom of their hard coded single usage case/environment. The test suite and the many tests are each individual and separate something that is not compatible with hardcoding a singleton.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top