¿Qué tienen de malo los singletons? [cerrado]

1984

El patrón Singleton es un miembro totalmente desembolsado del GoF 's libro de patrones , pero últimamente parece bastante huérfano por el mundo desarrollador. Todavía uso muchos singletons, especialmente para las clases de fábrica , y aunque debes tener un poco de cuidado con los problemas de subprocesos múltiples (como cualquier clase en realidad), no veo por qué son tan horribles.

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

Respalde sus respuestas con " hechos, referencias o experiencia específica "

m87
fuente
66
Tengo que decir que usar un diseño singleton me ha quemado recientemente, ya que he tratado de adaptar el código. Como lo hago en mi tiempo libre, soy casi demasiado vago para refactorizar esto. Malas noticias para la productividad.
Marcin
71
Hay muchas 'desventajas' en las respuestas, pero también me gustaría ver algunos buenos ejemplos de cuándo el patrón es bueno, para contrastar con lo malo ...
DGM
50
Escribí una publicación de blog sobre el tema hace unos meses: jalf.dk/blog/2010/03/… - y permítanme decirlo directamente. No puedo pensar personalmente en una sola situación en la que un singleton sea la solución correcta. Eso no significa que tal situación no exista, pero ... llamarlos raros es quedarse corto.
jalf
8
@AdamSmith no significa que tenga que hacerlo, pero significa que puede acceder de esa manera. Y si no tiene la intención de acceder así, entonces hay pocas razones para que sea un singleton en primer lugar. Entonces su argumento es efectivamente "no hay daño en hacer un singleton si no lo tratamos como un singleton. Sí, genial. Mi auto tampoco contamina si no conduzco en él. Pero es más fácil simplemente no adquirir un automóvil en primer lugar.;) (divulgación completa: en realidad no tengo un automóvil)
jalf
35
La peor parte de todo este tema es que las personas que odian los solteros raramente dan sugerencias concretas sobre qué usar. Los enlaces a artículos de revistas y blogs autoeditados a lo largo de este artículo de SO, por ejemplo, continúan y explican por qué no usar singletons (y todos son excelentes razones), pero son extremadamente escasos en reemplazos. Sin embargo, muchas ondas manuales. Aquellos de nosotros que tratamos de enseñar a los nuevos programadores por qué no usar singletons no tenemos muchos buenos contraejemplos de terceros para señalar, solo ejemplos inventados. Es agotador
Ti Strga

Respuestas:

1294

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 olor a código .

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

  3. Inherentemente hacen 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.

Jim Burger
fuente
324
No estoy de acuerdo contigo. Dado que los comentarios solo permiten 600 caracteres, he escrito una publicación de blog para comentar sobre esto, consulte el siguiente enlace. jorudolph.wordpress.com/2009/11/22/singleton-considerations
Johannes Rudolph
61
En los puntos 1 y 4, creo que los singletons son útiles, y de hecho casi perfectos para el almacenamiento en caché de datos (especialmente de un DB). El aumento en el rendimiento supera con creces las complejidades involucradas en las pruebas de unidades de modelado.
Dai Bok
56
@Dai Bok: "el almacenamiento en caché de datos (sobre todo a partir de una base de datos)" utilizar el patrón proxy para hacer esto ...
paxos1977
55
Wow, excelentes respuestas. Probablemente usé palabras demasiado agresivas aquí, así que por favor tenga en cuenta que estaba respondiendo una pregunta orientada negativamente. Mi respuesta estaba destinada a ser una breve lista de los 'anti patrones' que ocurren por el mal uso de Singleton. La divulgación completa; Yo también uso Singletons de vez en cuando. Hay preguntas más neutrales sobre SO que serían excelentes foros para cuando Singletons puede considerarse una buena idea. Por ejemplo, stackoverflow.com/questions/228164/…
Jim Burger
21
No son tan buenos para almacenar en caché en un entorno multiproceso. Puede derrotar fácilmente un caché con múltiples hilos que luchan por un recurso limitado. [mantenido por un singleton]
monksy
449

Los Singletons resuelven un (y solo un) problema.

Contención de recursos.

Si tienes algún recurso que

( 1 ) solo puede tener una única instancia, y

( 2 ) necesita 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 debe gestionarse.

Es raro que necesites un singleton. La razón por la que son malos es que se sienten globales y son miembros totalmente pagados del libro GoF Design Patterns .

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

S.Lott
fuente
43
El hardware también es un ejemplo, ¿verdad? Los sistemas integrados tienen una gran cantidad de hardware que puede usar singletons, ¿o quizás uno grande? <grin>
Jeff el
170
Totalmente de acuerdo. Hay una gran cantidad de conversaciones decididas sobre "esta práctica es mala" sin reconocer que la práctica puede tener su lugar. A menudo, la práctica es solo "mala" porque con frecuencia se usa mal. No hay nada intrínsecamente malo en el patrón Singleton siempre que se aplique de manera adecuada.
Damovisa
53
Realmente, los singletons por principio son muy raros (y una cola de impresora ciertamente no es una, y tampoco lo es un archivo de registro; consulte log4j). La mayoría de las veces, el hardware es un singleton por coincidencia y no por principio. Todo el hardware conectado a una PC es, en el mejor de los casos, un singleton coincidente (piense en varios monitores, ratones, impresoras, tarjetas de sonido). Incluso un detector de partículas de 500 millones de dólares es un singleton por coincidencia y restricciones de presupuesto, que no se aplican en el software, por lo tanto: no singleton. En telecomunicaciones, ni el número de teléfono ni el teléfono físico son singletons (piense en ISDN, call center).
digitalarbeiter
23
El hardware puede tener solo una instancia de una variedad de recursos, pero el hardware no es software. No hay razón para que un solo puerto serie en una placa de desarrollo deba modelarse como Singleton. De hecho, modelarlo solo hará que sea más difícil portar a la nueva placa que tiene dos puertos.
dash-tom-bang
19
¿Entonces escribirías dos clases idénticas, duplicando mucho código, solo para que puedas tener dos singletons que representen dos puertos? ¿Qué tal simplemente usando dos objetos SerialPort globales? ¿Qué tal no modelar el hardware como clases? ¿Y por qué usaría singletons, que también implican acceso global? ¿Desea que todas las funciones de su código puedan acceder al puerto serie?
jalf
352

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 otros que odian la idea de usar un global . He visto a varios desarrolladores hacer todo lo posible para evitar un global porque consideraron usar uno como una admisión de falla. 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, por lo tanto, úsela. Pero usarlo solo para jactarse de usar un patrón de diseño es tan estúpido como negarse a usarlo porque es simplemente global .

Phil Wright
fuente
17
El fallo que veo en Singleton es que la gente los usa en lugar de los globales porque de alguna manera son "mejores". El problema es (como lo veo), que las cosas que Singleton trae a la mesa en estos casos son irrelevantes. (Construir en el primer uso es trivial de implementar en un no singleton, por ejemplo, incluso si en realidad no está usando el constructor para hacerlo.)
dash-tom-bang
21
La razón por la que "nosotros" los menospreciamos es porque "nosotros" con mucha frecuencia los vemos mal utilizados, y con demasiada frecuencia. "Nosotros" sabemos que tienen su lugar de causa.
Bjarke Freund-Hansen
55
@ Phil, Usted dijo "de vez en cuando puede encontrar que es la solución ideal y, por lo tanto, úsela". Ok, entonces, ¿exactamente en qué caso encontraríamos útil un singleton?
Pacerier
22
@Pacerier, siempre que se cumplan todas las condiciones siguientes: (1) solo necesita uno de algo, (2) debe pasar esa única cosa como argumento en una gran cantidad de llamadas a métodos, (3) está dispuesto a aceptar un posibilidad de tener que refactorizar algún día a cambio de una reducción inmediata en el tamaño y la complejidad de su código al no pasarlo por todas partes.
antinome
18
No creo que esto responda nada, solo dice que "a veces podría encajar, otras no". OK, pero ¿por qué y cuándo? ¿Qué hace que esta respuesta sea más que un argumento para la moderación ?
Guildenstern
219

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

Los singletons son mentirosos patológicos tiene un ejemplo de prueba de unidad que ilustra cómo los singletons pueden dificultar la determinación de cadenas de dependencia e iniciar o probar una aplicación. Es un ejemplo bastante extremo de abuso, pero el punto que él hace es 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 tienen todos los Singletons Gone? 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 malos denunciados en el primer artículo.

jason
fuente
8
Los artículos de Misko sobre el tema son lo mejor que hay en este momento.
Chris Mayer
22
El primer enlace en realidad no aborda un problema con singletons, sino que supone una dependencia estática dentro de la clase. Es posible arreglar el ejemplo dado pasando parámetros, y aún así usar singletons.
DGM
17
@DGM: Exactamente, de hecho, existe una enorme desconexión lógica entre la parte 'racional' del artículo y la parte 'Los Singleton son la causa'.
Harper Shelby
1
El artículo de Misko CreditCard es un ejemplo extremo de mal uso de este patrón.
Alex
2
Al leer el segundo artículo, los Singletons son en realidad parte del modelo de objeto descrito. Sin embargo, en lugar de ser accesibles globalmente, estos son privados para los objetos Factory.
FruitBreak
121

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

La gente piensa que Singleton es malvado porque lo está usando para los globales. Es a causa de esta confusión que Singleton es menospreciado. Por favor, no confunda Singletons y globals. Si se usa para el propósito para el que fue diseñado, obtendrá beneficios extremos del patrón Singleton.

Cem Catikkas
fuente
20
¿Cuál es esa instancia, disponible en toda la aplicación? Oh. Mundial . "Singleton no es un patrón para envolver los globales" es ingenuo o engañoso, ya que, por definición , el patrón envuelve una clase alrededor de una instancia global.
cHao
26
Por supuesto, puede crear una instancia de la clase cuando se inicia su aplicación e inyectar esa instancia, a través de una interfaz, en cualquier cosa que la use. La implementación no debería importarle que solo pueda haber una.
Scott Whitlock
44
@Dainius: Realmente no hay, al final. Claro, no puedes reemplazar arbitrariamente la instancia con otra. (Excepto por esos momentos inductores de facepalm cuando lo haces . De hecho, he visto setInstancemétodos antes.) Sin embargo, eso apenas importa: ese pito que "necesitaba" un singleton tampoco sabía nada sobre la encapsulación o lo que está mal con estado global mutable, por lo que ayudó (?) proporcionó setters para cada. soltero. campo. (Y sí, esto sucede. Mucho . Casi todos los singleton que he visto en la naturaleza eran mutables por diseño, y a menudo de manera
vergonzosa
44
@Dainius: En gran medida, ya lo tenemos. "Prefiero la composición sobre la herencia" ha sido una cosa desde hace bastante tiempo. Sin embargo, cuando la herencia es demostrablemente la mejor solución, por supuesto, es libre de usarla. Lo mismo ocurre con los singletons, globals, threading, gotoetc. Pueden funcionar en muchos casos, pero, francamente, "funciona" no es suficiente: si quiere ir en contra de la sabiduría convencional, será mejor que pueda demostrar cómo su enfoque Es mejor que las soluciones convencionales. Y aún no he visto tal caso para el patrón Singleton.
cHao
3
Para que no nos hablemos, no solo estoy hablando de una instancia disponible a nivel mundial. Hay muchos casos para eso. De lo que estoy hablando (especialmente cuando digo "capital-S Singleton") es el patrón Singleton de GoF, que incorpora esa instancia global única en la clase misma, la expone a través de un getInstancemétodo o un nombre similar, y evita la existencia de un segunda instancia Francamente, en ese punto, es posible que ni siquiera tenga una instancia.
cHao
72

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

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

Así que básicamente:

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

más bien que:

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 generalmente se rompen, y los patrones no se deben aplicar de ninguna manera sin pensarlo.

Mike Stone
fuente
17
Je, si haces esto en todas partes, entonces tendrías que pasar una referencia al singelton en todas partes también, y por lo tanto ya no tienes un singleton. :) (Lo cual suele ser algo bueno de la OMI.)
Bjarke Freund-Hansen
2
@ BjarkeFreund-Hansen - Tonterías, ¿de qué estás hablando? Un singleton es simplemente una instancia de una clase que se instaura una vez. Hacer referencia a un Singleton de este tipo no copia el objeto real, solo hace referencia a él, todavía tiene el mismo objeto (léase: Singleton).
M. Mimpen
2
@ M.Mimpen: No, un Singleton con mayúscula (que es lo que se está discutiendo aquí) es una instancia de una clase que (a) garantiza que solo existirá una instancia, y (b) se accede a través de la propia clase Punto de acceso global incorporado. Si ha declarado que nada debería llamar getInstance(), entonces (b) ya no es del todo cierto.
cHao
2
@ cHao No te sigo o no entiendes a quién le comento, que es para Bjarke Freund-Hansen. Bjarke afirma que tener varias referencias de un singleton tiene varios singletons. Eso ciertamente no es cierto ya que no hay copias profundas.
M. Mimpen
66
@ M.Mimpen: Aprovecho su comentario para referirme más al efecto semántico. Una vez que prohibe las llamadas getInstance(), ha descartado efectivamente la única diferencia útil entre el patrón Singleton y una referencia ordinaria. En lo que respecta al resto del código, la soltería ya no es una propiedad. Solo la persona que llama getInstance()debe saber o incluso importar cuántas instancias hay. Con solo una persona que llama, le cuesta más esfuerzo y flexibilidad a la clase imponer de manera confiable la soltería que a la persona que llama simplemente almacenar una referencia y reutilizarla.
cHao
69

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

Los singleton también son un problema desde una perspectiva de prueba. Tienden a dificultar la escritura de pruebas unitarias aisladas. La inversión de control (IoC) y la 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 entorno de recolección de basura, los singletons pueden convertirse rápidamente en un problema con respecto a la administración de memoria.

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

Kimoz
fuente
44
Sé que es hilo de muchos años. hola @Kimoz u dijo: - los singletons pueden convertirse rápidamente en un problema con respecto a la gestión de la memoria. quisiera explicar con más detalle qué tipo de problema puede surgir con respecto a la recolección de basura y singleton
Thomas
@Kimoz, la pregunta es "¿Por qué el patrón singleton no es un problema en sí mismo?" y simplemente ha repetido el punto pero no ha proporcionado ni un solo caso de uso válido del patrón singleton.
Pacerier
@Thomas, porque un singleton por definición existe en una sola instancia. Por lo tanto, a menudo es complejo asignar la única referencia a nulo. Se puede hacer, pero significa que usted controla completamente el punto después del cual el singleton no se usa en su aplicación. Y esto es raro y, por lo general, es todo lo contrario de lo que buscan los entusiastas de Singleton: una forma simple de hacer que una única instancia sea siempre accesible. En algunos marcos DI como Guice o Dagger, no es posible deshacerse de un singleton y permanece para siempre en la memoria. (Aunque los contenedores provistos de singletons son mucho mejores que los caseros).
Snicolas
54

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 burlarse ni tropezarse. 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 de inversión de control .

Peter Mortensen
fuente
99
Eso suena más como un problema con las pruebas unitarias que pueden probar objetos (unidades), funciones (unidades), bibliotecas completas (unidades), pero fallan con cualquier cosa estática en la clase (también unidades).
v010dya
2
¿no se supone que debes mover todas las referencias externas de todos modos? Si es así, ¿cuál es el problema de moc singleton? Si no, ¿realmente estás haciendo pruebas unitarias?
Dainius
@Dainius: burlarse de las instancias es mucho menos problemático que burlarse de las clases. Podrías extraer la clase bajo prueba del resto de la aplicación y probar con una Singletonclase falsa . Sin embargo, eso complica enormemente el proceso de prueba. Por un lado, ahora debe poder descargar las clases a voluntad (no es realmente una opción en la mayoría de los idiomas) o iniciar una nueva máquina virtual para cada prueba (lea: las pruebas pueden tomar miles de veces más). Sin embargo, para dos, la dependencia Singletones un detalle de implementación que ahora se está filtrando en todas sus pruebas.
cHao
Powermock puede burlarse de cosas estáticas.
Snicolas
¿burlarse de un objeto significa crear un objeto real? Si burlarse no crea un objeto real, ¿por qué importa si la clase es singleton o el método es estático?
Arun Raaj
45

Los singletons también son malos cuando se trata de agrupamiento . Porque entonces, ya no tienes "exactamente un singleton" en tu aplicación.

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

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 único 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 se supone que no es un singleton: 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 del 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.

Uooo
fuente
44
Si no sabe cómo implementar Singleton, no debe hacerlo. Si no sabe lo que está haciendo, debe encontrar eso primero, y solo después de eso haga lo que necesita.
Dainius
3
Esto es interesante, tengo una pregunta. Entonces, ¿cuál es exactamente el problema si los singletons, cada uno en una máquina / JVM diferente, se conectan a una sola base de datos? El alcance de Singletons es solo para esa JVM particular, y eso sigue siendo cierto incluso en un clúster. En lugar de decir filosóficamente que esta situación particular es mala porque nuestra intención era un solo objeto en toda la aplicación, me complacería ver cualquier problema técnico que pueda surgir debido a este acuerdo.
Saurabh Patil
39
  1. Se usa fácilmente (ab) como una variable global.
  2. Las clases que dependen de singletons son relativamente más difíciles de probar en forma aislada.
jop
fuente
33

El monopolio es el demonio y los singletons con estado no solo de lectura / mutable son el problema 'real' ...

Después de leer Singletons son mentirosos patológicos, como se sugiere en la respuesta de Jason, me encontré con este pequeño dato que proporciona el mejor ejemplo presentado de cómo los singletons a menudo se usan mal.

Global es malo porque:

  • a. Causa conflicto de espacio de nombres
  • si. Expone el estado de manera injustificada

Cuando se trata de Singletons

  • a. La forma explícita OO de llamarlos evita los conflictos, así que señale a. no es un problema
  • si. Los singletons sin estado son (como las fábricas) no son un problema. Los singletons con estado pueden caer nuevamente en dos categorías, aquellas que son inmutables o que escriben una vez y leen muchas (archivos de configuración / propiedad). Estos no son malos. Singletons mutables, que son como titulares de referencias, son de los que estás hablando.

En la última declaración se está refiriendo al concepto del blog de "los solteros son mentirosos".

¿Cómo se aplica esto al Monopolio?

Para comenzar un juego de monopolio, primero:

  • establecemos las reglas primero para que todos estén en la misma página
  • todos tienen un comienzo igual al comienzo del juego
  • solo se presenta un conjunto de reglas para evitar confusiones
  • las reglas no pueden cambiar durante el juego

Ahora, para cualquiera que realmente no haya jugado al monopolio, estos estándares son ideales en el mejor de los casos. Una derrota en el monopolio es difícil de tragar porque, el monopolio se trata de dinero, si pierdes tienes que ver minuciosamente al resto de los jugadores terminar el juego, y las pérdidas suelen ser rápidas y aplastantes. Por lo tanto, las reglas generalmente se tuercen en algún momento para servir el interés propio de algunos de los jugadores a expensas de los demás.

Entonces estás jugando al monopolio con tus amigos Bob, Joe y Ed. Estás construyendo rápidamente tu imperio y consumiendo participación de mercado a un ritmo exponencial. Tus oponentes se debilitan y comienzas a oler sangre (en sentido figurado). Su amigo Bob invirtió todo su dinero en bloquear todas las propiedades de bajo valor posibles, pero no está recibiendo un alto retorno de la inversión como esperaba. Bob, como un golpe de mala suerte, aterriza en su Boardwalk y es eliminado del juego.

Ahora el juego pasa de tirar dados amistosamente a asuntos serios. Bob se ha convertido en el ejemplo del fracaso y Joe y Ed no quieren terminar como 'ese tipo'. Entonces, siendo el jugador líder, de repente, te conviertes en el enemigo. Joe y Ed comienzan a practicar intercambios debajo de la mesa, inyecciones de dinero detrás de la espalda, intercambios de casas infravalorados y, en general, cualquier cosa que lo debilite como jugador hasta que uno de ellos llegue a la cima.

Luego, en lugar de que uno de ellos gane, el proceso comienza de nuevo. De repente, un conjunto finito de reglas se convierte en un objetivo en movimiento y el juego degenera en el tipo de interacciones sociales que constituirían la base de cada reality show de televisión de alto nivel desde Survivor. Por qué, porque las reglas están cambiando y no hay consenso sobre cómo / por qué / qué se supone que representan, y lo que es más importante, no hay una sola persona que tome las decisiones. Cada jugador en el juego, en ese momento, está haciendo sus propias reglas y se produce el caos hasta que dos de los jugadores están demasiado cansados ​​para mantener la farsa y rendirse lentamente.

Entonces, si un libro de reglas para un juego representa con precisión un singleton, el libro de reglas de monopolio sería un ejemplo de abuso.

¿Cómo se aplica esto a la programación?

Además de todos los problemas obvios de sincronización y seguridad de subprocesos que presentan los singletons mutables ... Si tiene un conjunto de datos, que puede ser leído / manipulado por múltiples fuentes diferentes al mismo tiempo y existe durante la vida útil de la ejecución de la aplicación, Probablemente sea un buen momento para dar un paso atrás y preguntar "¿Estoy usando el tipo correcto de estructura de datos aquí".

Personalmente, he visto a un programador abusar de un singleton al usarlo como una especie de almacén de bases de datos entrelazadas en una aplicación. Habiendo trabajado en el código directamente, puedo dar fe de que fue lento (debido a todos los bloqueos de hilo necesarios para que sea seguro para el hilo) y una pesadilla para trabajar (debido a la naturaleza impredecible / intermitente de los errores de sincronización), y casi imposible de probar bajo condiciones de 'producción'. Claro, un sistema podría haberse desarrollado utilizando sondeo / señalización para superar algunos de los problemas de rendimiento, pero eso no resolvería los problemas con las pruebas y, ¿por qué molestarse cuando una base de datos 'real' ya puede lograr la misma funcionalidad en un sistema mucho más robusto? / manera escalable.

Un Singleton es solo una opción si necesita lo que proporciona un Singleton. Una instancia de solo lectura de escritura de un objeto. Esa misma regla también debería conectarse en cascada con las propiedades / miembros del objeto.

Evan Plaice
fuente
1
¿Qué pasa si singleton cobra algunos datos?
Yola
@Yola Reduciría el número de escrituras si el singleton se programara para actualizarse en un horario predeterminado y / o fijo, reduciendo así la contención de hilos. Aún así, no podrá probar con precisión ninguno de los códigos que interactúan con el singleton a menos que se burle de una instancia que no sea singleton que simule el mismo uso. La gente de TDD probablemente encajaría, pero funcionaría.
Evan Plaice
@EvanPlaice: Incluso con un simulacro, tendría algunos problemas con el código que dice Singleton.getInstance(). Un lenguaje que admita la reflexión podría solucionarlo configurando el campo donde se almacena la instancia de One True. Sin embargo, en mi opinión, las pruebas se vuelven un poco menos confiables una vez que has empezado a jugar con el estado privado de otra clase.
cHao
28

¡Singleton no se trata de una sola instancia!

A diferencia de otras respuestas, no quiero hablar sobre lo que está mal con Singletons, ¡sino mostrarles lo poderosos e increíbles que son cuando se usan correctamente!

  • Problema : Singleton puede ser un desafío en un entorno de subprocesos múltiples
    Solución : utilice un proceso de arranque de subproceso único para inicializar todas las dependencias de su singleton.
  • Problema : es difícil burlarse de los singletons.
    Solución : utilice el método Patrón de fábrica para burlarse

Puede asignar MyModela la TestMyModelclase que lo hereda, en todas partes, cuando MyModelse inyectará, se le TestMyModelinsertará. - Problema : los Singletons pueden causar pérdidas de memoria ya que nunca se eliminaron.
Solución : Bueno, ¡deséchalos! Implemente una devolución de llamada en su aplicación para desechar correctamente un singletons, debe eliminar todos los datos vinculados a ellos y finalmente: eliminarlos de la fábrica.

Como dije en el título, singleton no se trata de una sola instancia.

  • Singletons mejora la legibilidad : puedes mirar tu clase y ver qué singleton inyectó para descubrir cuáles son sus dependencias.
  • Singletons mejora el mantenimiento : una vez que eliminó una dependencia de una clase, acaba de eliminar alguna inyección de singleton, no necesita ir y editar un gran enlace de otras clases que simplemente movieron su dependencia (este es un código maloliente para mí @ Jim Burger )
  • Singletons mejora la memoria y el rendimiento : cuando ocurre algo en su aplicación y se necesita una larga cadena de devoluciones de llamada, está desperdiciando memoria y rendimiento, al usar Singleton está cortando al intermediario y mejora su rendimiento y uso de memoria ( evitando asignaciones innecesarias de variables locales).
Ilya Gazman
fuente
2
Esto no resuelve mi problema principal con Singletons, que es que permiten el acceso al estado global desde cualquiera de las miles de clases en su proyecto.
LegendLength
8
Ese sería el propósito ...
Ilya Gazman
LegendLength ¿Por qué está mal eso? Por ejemplo, en mi aplicación tengo un Settingsobjeto singleton al que se puede acceder desde cualquier widget para que cada widget sepa cómo formatear los números mostrados. Si no fuera un objeto accesible globalmente, tendría que inyectarlo en el constructor a todos y cada uno de los widgets en el constructor y mantener la referencia a él como una variable miembro. Esta es una terrible pérdida de memoria y tiempo.
VK
23

Mi respuesta sobre cómo los Singleton son malos es siempre, "son difíciles de hacer bien". Muchos de los componentes fundamentales de los lenguajes son singletons (clases, funciones, espacios de nombres e incluso operadores), al igual que los componentes de otros aspectos de la informática (localhost, ruta predeterminada, sistema de archivos virtual, etc.), y no es accidental. Si bien ocasionan problemas y frustración de vez en cuando, también pueden hacer que muchas cosas funcionen MUCHO mejor.

Los dos errores más grandes que veo son: tratarlo como algo global y no definir el cierre Singleton.

Todos hablan de Singleton como globales, porque básicamente lo son. Sin embargo, gran parte (lamentablemente, no todo) de la maldad en un mundo no proviene intrínsecamente de ser global, sino de cómo lo usas. Lo mismo va para Singletons. En realidad, más aún, ya que "instancia única" realmente no tiene que significar "accesible a nivel mundial". Es más un subproducto natural, y dado todo lo malo que sabemos que proviene de él, no deberíamos tener tanta prisa por explotar la accesibilidad global. Una vez que los programadores ven un Singleton, siempre parecen acceder a él directamente a través de su método de instancia. En su lugar, debe navegar hacia él como lo haría con cualquier otro objeto. La mayoría del código ni siquiera debería saber que se trata de un Singleton (acoplamiento flojo, ¿verdad?). Si solo un pequeño fragmento de código accede al objeto como si fuera global, se deshace mucho daño.

El contexto Singleton también es realmente importante. La característica definitoria de un Singleton es que hay "solo uno", pero la verdad es que es "solo uno" dentro de algún tipo de contexto / espacio de nombres. Por lo general, son uno de: uno por subproceso, proceso, dirección IP o clúster, pero también pueden ser uno por procesador, máquina, espacio de nombres de idioma / cargador de clases / lo que sea, subred, Internet, etc.

El otro error, menos común, es ignorar el estilo de vida Singleton. El hecho de que solo haya uno no significa que un Singleton es un omnipotente "siempre fue y siempre será", ni es generalmente deseable (los objetos sin principio y fin violan todo tipo de suposiciones útiles en el código, y solo deben emplearse en la más desesperada de las circunstancias.

Si evita esos errores, Singletons aún puede ser un PITA, aunque está listo para ver que muchos de los peores problemas se mitigan significativamente. Imagine un Java Singleton, que se define explícitamente como una vez por cargador de clases (lo que significa que necesita una política de seguridad de subprocesos), con métodos definidos de creación y destrucción y un ciclo de vida que dicta cuándo y cómo se invocan, y cuyo método de "instancia" tiene protección de paquete, por lo que generalmente se accede a través de otros objetos no globales. Sigue siendo una fuente potencial de problemas, pero ciertamente mucho menos problemas.

Lamentablemente, en lugar de enseñar buenos ejemplos de cómo hacer Singletons. Enseñamos malos ejemplos, dejamos que los programadores los usen por un tiempo y luego les digamos que son un mal patrón de diseño.

Christopher Smith
fuente
23

Ver Wikipedia Singleton_pattern

Algunas personas también lo consideran un antipatrón, que sienten que se usa en exceso, lo que introduce limitaciones innecesarias en situaciones en las que no se requiere una sola instancia de una clase. [1] [2] [3] [4]

Referencias (solo referencias relevantes del artículo)

  1. ^ Alex Miller. Patrones que odio # 1: Singleton , julio de 2007
  2. ^ Scott Densmore. Por qué los solteros son malvados , mayo de 2004
  3. ^ Steve Yegge. Singletons considerados estúpidos , septiembre de 2004
  4. ^ JB Rainsberger, IBM. Usa tus singletons sabiamente , julio de 2001
GUI Junkie
fuente
8
Una descripción sobre el patrón no explica por qué se considera malvado ...
Jrgns
2
Difícilmente justo: "Algunas personas también lo consideran un antipatrón, que sienten que se usa en exceso, lo que introduce limitaciones innecesarias en situaciones en las que no se requiere una única instancia de una clase". Mira las referencias ... De todos modos, tengo RTFM para mí.
GUI Junkie
17

No es que los singletons en sí sean malos, pero el patrón de diseño GoF sí lo es. El único argumento realmente válido es que el patrón de diseño de GoF no se presta en lo que respecta a las pruebas, especialmente si las pruebas se ejecutan en paralelo.

Usar una sola instancia de una clase es una construcción válida siempre que aplique los siguientes medios en el código:

  1. Asegúrese de que la clase que se utilizará como singleton implemente una interfaz. Esto permite implementar stubs o simulacros utilizando la misma interfaz

  2. Asegúrese de que el Singleton sea seguro para subprocesos. Eso es un hecho.

  3. El singleton debe ser de naturaleza simple y no demasiado complicado.

  4. Durante el tiempo de ejecución de su aplicación, donde los singletons deben pasarse a un objeto dado, use una fábrica de clases que construya ese objeto y haga que la fábrica de clases pase la instancia de singleton a la clase que lo necesita.

  5. Durante las pruebas y para garantizar un comportamiento determinista, cree la clase singleton como instancia separada, ya sea como la clase en sí misma o como un stub / simulacro que implemente su comportamiento y páselo como está a la clase que lo requiere. No use el factor de clase que crea ese objeto bajo prueba que necesita el singleton durante la prueba, ya que pasará la única instancia global del mismo, lo que anula el propósito.

Hemos utilizado Singletons en nuestras soluciones con un gran éxito que es comprobable y garantiza un comportamiento determinista en flujos de prueba paralelos.

usuario1578119
fuente
+1, finalmente , una respuesta que aborda cuándo un singleton puede ser válido.
Pacerier
16

Me gustaría abordar los 4 puntos en la respuesta aceptada, espero que alguien pueda explicar por qué estoy equivocado.

  1. ¿Por qué es malo ocultar dependencias en tu código? Ya hay docenas de dependencias ocultas (llamadas de tiempo de ejecución C, llamadas a API de sistema operativo, llamadas a funciones globales), y las dependencias singleton son fáciles de encontrar (busque por ejemplo ()).

    "Hacer algo global para evitar pasarlo es un olor a código". ¿Por qué no se pasa algo para evitar que sea un solo olor a código?

    Si está pasando un objeto a través de 10 funciones en una pila de llamadas solo para evitar un singleton, ¿es genial?

  2. Principio de responsabilidad única: creo que esto es un poco vago y depende de su definición de responsabilidad. Una pregunta relevante sería, ¿por qué es importante agregar esta "responsabilidad" específica a una clase?

  3. ¿Por qué pasar un objeto a una clase lo hace más estrechamente acoplado que usar ese objeto como un singleton dentro de la clase?

  4. ¿Por qué cambia cuánto dura el estado? Los Singletons pueden crearse o destruirse manualmente, por lo que el control todavía está allí, y puede hacer que la vida sea la misma que la vida de un objeto que no sea Singleton.

En cuanto a las pruebas unitarias:

  • no todas las clases necesitan ser probadas
  • no todas las clases que necesitan ser probadas por unidad necesitan cambiar la implementación del singleton
  • si lo hacen necesario análisis unidad y la necesidad de hacer cambiar la implementación, es fácil cambiar una clase de uso de un producto único a tener el singleton se le ha pasado a través de la inyección de dependencia.
Jon
fuente
1
1. ¿Todas esas dependencias ocultas? Esos también son malos. Las dependencias ocultas siempre son malas. Pero en el caso de CRT y OS, ya están allí, y son la única forma de hacer algo. (Intente escribir un programa en C sin usar el tiempo de ejecución o el sistema operativo). Esa capacidad de hacer cosas supera con creces sus aspectos negativos. Los Singletons en nuestro código no obtienen ese lujo; Dado que están firmemente dentro de nuestra esfera de control y responsabilidad, cada uso (léase: cada dependencia oculta adicional) debe ser justificable como la única forma razonable de hacer las cosas. Muy, muy pocos de ellos lo son.
cHao
2. "Responsabilidad" se define típicamente como "razón para cambiar". Un singleton termina administrando su vida útil y haciendo su trabajo real. Si cambia la forma en que se realiza el trabajo o cómo se construye el gráfico de objetos, debe cambiar la clase. Pero si tiene otro código, cree el gráfico de objetos, y su clase simplemente hace su trabajo real, ese código de inicialización puede configurar el gráfico de objetos como quiera. Todo es mucho más modular y comprobable, porque puede insertar dobles de prueba y derribar todo a voluntad, y ya no depende de partes móviles ocultas.
cHao
1
@ cHao: 1. Es bueno que reconozca que la "capacidad de hacer cosas supera con creces sus aspectos negativos". Un ejemplo sería un marco de registro. Es malo ordenar pasar un objeto de registro global por inyección de dependencia a través de capas de llamadas de función si esto significa que se desalienta a los desarrolladores a iniciar sesión. Por lo tanto, singleton. 3. Su estrecho punto de acoplamiento solo es relevante si desea que los clientes de la clase controlen el comportamiento a través del polimorfismo. Ese no suele ser el caso.
Jon
2
4. No estoy seguro de que "no se pueda destruir manualmente" es una implicación lógica de "solo puede ser una instancia". Si así es como define singleton, entonces no estamos hablando de lo mismo. Todas las clases no deben ser probadas por unidad Esa es una decisión comercial, y a veces el costo de tiempo de comercialización o desarrollo tendrá prioridad.
Jon
1
3. Si no quieres polimorfismo, entonces ni siquiera necesitas una instancia. También podría convertirlo en una clase estática, porque de todos modos se está vinculando a un solo objeto y a una sola implementación, y al menos la API no le está mintiendo tanto.
cHao
15

Vince Huston tiene estos criterios, que me parecen razonables:

Singleton debe considerarse solo si se cumplen los tres criterios siguientes:

  • La propiedad de la instancia única no se puede asignar razonablemente
  • La inicialización perezosa es deseable
  • El acceso global no se proporciona de otra manera

Si la propiedad de la instancia única, cuándo y cómo ocurre la inicialización, y el acceso global no son problemas, Singleton no es lo suficientemente interesante.

js.
fuente
14

Los singletons son malos desde un punto de vista purista.

Desde un punto de vista práctico, un singleton es una compensación entre tiempo de desarrollo y complejidad .

Si sabe que su aplicación no cambiará tanto, están bastante bien. Solo sepa que es posible que necesite refactorizar las cosas si sus requisitos cambian de manera inesperada (lo cual está bastante bien en la mayoría de los casos).

Los singletons a veces también complican las pruebas unitarias .

tacone
fuente
3
Mi experiencia es que comenzar con singletons realmente te hará daño incluso a corto plazo, sin contar el largo plazo. Este efecto podría ser menor si la aplicación ya existe por algún tiempo, y probablemente ya esté infestada con otros singletons. ¿Empezando desde cero? ¡Evítalos a toda costa! ¿Quieres una sola instancia de un objeto? Deje que una fábrica gestione la creación de instancias de este objeto.
Sven
1
AFAIK Singleton es un método de fábrica. Por lo tanto, no entiendo tu recomendación.
tacone
3
"A factory"! = "Un método factory_ que no se puede separar de otras cosas útiles en la misma clase"
Sven
13

No hay nada intrínsecamente incorrecto en el patrón, suponiendo que se esté utilizando para algún aspecto de su modelo que sea verdaderamente único.

Creo que la reacción se debe a su uso excesivo que, a su vez, se debe al hecho de que es el patrón más fácil de entender e implementar.

Ben Hoffstein
fuente
66
Creo que la reacción tiene más que ver con las personas que practican pruebas unitarias formalizadas al darse cuenta de que son una pesadilla con la que lidiar.
Jim Burger
1
No estoy seguro de por qué esto está en -1. No es la respuesta más descriptiva, pero tampoco está equivocado.
Outlaw Programmer
13

No voy a comentar sobre el argumento del bien / el mal, pero no los he usado desde que llegó la primavera . El uso de la inyección de dependencia ha eliminado mis requisitos para singleton, servicelocators y fábricas. Me parece un entorno mucho más productivo y limpio, al menos para el tipo de trabajo que hago (aplicaciones web basadas en Java).

Peter Mortensen
fuente
3
¿no son los frijoles de primavera, por defecto, Singletons?
delgado
3
Sí, pero me refiero a 'codificar' singletons. No he 'escrito un singleton' (es decir, con un constructor privado yada yada yada según el patrón de diseño), pero sí, con spring estoy usando una sola instancia.
Prule
44
así que cuando otros lo hacen, está bien (si usaré eso después), pero si otros lo hacen y no lo usaré, ¿es malo?
Dainius
11

Singleton es un patrón y se puede usar o abusar como cualquier otra herramienta.

La parte mala de un singleton es generalmente el usuario (o debería decir el uso inapropiado de un singleton para cosas para las que no está diseñado). El mayor delincuente está usando un singleton como una variable global falsa.

Loki Astari
fuente
1
Gracias Loki :) Exactamente mi punto. Toda la caza de brujas me recuerda el debate sobre el goto. Las herramientas son para personas que saben cómo usarlas; usar una herramienta que no le gusta puede ser peligroso para usted, así que evítelo, pero NO le diga a otros que no lo usen / que no aprendan a usarlo correctamente. No soy exactamente "pro-singleton", pero me gusta el hecho de que tengo una herramienta como esa y puedo sentir dónde es apropiado usarla. Período.
dkellner
8

Cuando escribe código usando singletons, digamos, un registrador o una conexión de base de datos, y luego descubre que necesita más de un registro o más de una base de datos, está en problemas.

Los Singletons hacen que sea muy difícil pasar de ellos a objetos normales.

Además, es demasiado fácil escribir un singleton que no sea seguro para subprocesos.

En lugar de usar singletons, debe pasar todos los objetos de utilidad necesarios de una función a otra. Eso se puede simplificar si los envuelve en un objeto auxiliar, como este:

void some_class::some_function(parameters, service_provider& srv)
{
    srv.get<error_logger>().log("Hi there!");
    this->another_function(some_other_parameters, srv);
}
Roman Odaisky
fuente
44
Pasar argumentos para cada método es brillante, debería ir al menos a las 10 mejores formas de contaminar su API.
Dainius
Ese es un inconveniente obvio, y uno que debería haber sido manejado por el lenguaje, por medio de argumentos que de alguna manera se propagan en llamadas anidadas, pero en ausencia de tal soporte, debe hacerse manualmente. Tenga en cuenta que incluso los singletons naturales, como un objeto que representa el reloj del sistema, pueden causar problemas. Por ejemplo, ¿cómo va a cubrir el código dependiente del reloj (piense en un medidor de electricidad de tarifa múltiple) con pruebas?
Roman Odaisky
depende de lo que esté probando, si no está probando singleton, por qué le importa cómo se comporta, si sus 2 objetos remotos dependen el uno del otro, no es un problema singleton.
Dainius
¿Podría indicar qué idioma se propagaría en llamadas anidadas?
Dainius
1
Si tiene un módulo que depende de otro y no sabe / no puede moverlo, tendrá dificultades independientemente de si es único o no. Las personas usan la herencia de manera frecuente, donde deberían usar la composición, pero usted no dice que la herencia es mala, y la POO debe evitarse a toda costa, porque hay muchas personas cometiendo errores de diseño allí, ¿o usted?
Dainius
8

El problema con los singletons es la cuestión del alcance ampliado y, por lo tanto, del acoplamiento . No se puede negar que hay algunas situaciones en las que se necesita acceso a una sola instancia, y se puede lograr de otras maneras.

Ahora prefiero diseñar alrededor de un contenedor de inversión de control (IoC) y permitir que las vidas sean controladas por el contenedor. Esto le brinda el beneficio de que las clases que dependen de la instancia desconocen el hecho de que hay una sola instancia. La vida útil del singleton se puede cambiar en el futuro. Una vez que el ejemplo que encontré recientemente fue un ajuste fácil de un solo subproceso a varios subprocesos.

FWIW, si es un PIA cuando intentas probarlo en la unidad, entonces se convertirá en PIA cuando intentes depurarlo, corregirlo o mejorarlo.

Mark Lindell
fuente
7

Los singletons NO son malos. Solo es malo cuando haces algo globalmente único que no es globalmente único.

Sin embargo, hay "servicios de ámbito de aplicación" (piense en un sistema de mensajería que hace que los componentes interactúen): esto LLAMA para un singleton, una "MessageQueue" - clase que tiene un método "SendMessage (...)".

Luego puede hacer lo siguiente desde todas partes:

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

Y, por supuesto, hacer:

MessageQueue.Current.RegisterReceiver (este);

en clases que implementan IMessageReceiver.

StormianRootSolver
fuente
66
Y si quiero crear una segunda cola de mensajes, con un alcance más pequeño, ¿por qué no debería permitirme reutilizar su código para crearlo? Un singleton lo impide. Pero si acaba de crear una clase de cola de mensajes normal, y luego creó una instancia global para que actúe como "ámbito de aplicación", podría crear una segunda instancia para otro uso. Pero si hace que la clase sea un singleton, tendría que escribir una segunda clase de cola de mensajes.
jalf
1
Además, ¿por qué no deberíamos simplemente tener una CustomerOrderList global para poder llamarla bien desde cualquier lugar como MessageQueue? Creo que la respuesta es la misma para ambos: efectivamente está haciendo una variable global.
LegendLength
7

Demasiadas personas colocan objetos que no son seguros para subprocesos en un patrón singleton. He visto ejemplos de un DataContext ( LINQ to SQL ) realizado en un patrón singleton, a pesar de que el DataContext no es seguro para subprocesos y es puramente un objeto de unidad de trabajo.

Peter Mortensen
fuente
mucha gente escribe código inseguro de subprocesos múltiples, ¿eso significa que debemos eliminar los subprocesos?
Dainius
@Dainius: De hecho, sí. En mi opinión, el modelo de concurrencia predeterminado debe ser multiproceso, con una forma para que dos procesos (1) pasen mensajes entre sí fácilmente y / o (2) compartan memoria según sea necesario. El enhebrado es útil si desea compartir todo , pero en realidad nunca lo desea. Podría emularse compartiendo todo el espacio de direcciones, pero eso también se consideraría un antipatrón.
cHao
@Dainius: Y, por supuesto, eso supone que se necesita concurrencia honesta a la bondad. A menudo, todo lo que desea es poder hacer una cosa mientras espera que el sistema operativo haga otra cosa. (Actualizando la IU mientras se lee desde un socket, por ejemplo). Una API asíncrona decente podría hacer innecesario el subproceso completo en la gran mayoría de los casos.
cHao
así que si tiene una gran matriz de datos, que necesita un proceso, es mejor hacerlo en un solo hilo, porque para muchas personas podría hacerlo mal ...
Dainius
@Dainius: En muchos casos, sí. (El subproceso podría en realidad ralentizarlo , si agrega sincronización a la mezcla. Este es un excelente ejemplo de por qué el subprocesamiento múltiple no debería ser el primer pensamiento de la mayoría de las personas). En otros casos, sería mejor tener dos procesos que compartan solo Las cosas necesarias. Por supuesto, tendría que organizar los procesos para compartir memoria. Pero, francamente, lo veo como algo bueno , mucho mejor, al menos, que el modo predeterminado de compartir todo. Requiere que diga explícitamente (y así, idealmente, saber) qué partes se comparten y, por lo tanto, qué partes deben ser seguras para subprocesos.
cHao
6

Aquí hay una cosa más sobre los singletons que nadie dijo todavía.

En la mayoría de los casos, "singletonity" es un detalle de implementación para alguna clase más que una característica de su interfaz. La inversión del contenedor de control puede ocultar esta característica a los usuarios de la clase; solo necesita marcar su clase como singleton (con @Singletonanotaciones en Java, por ejemplo) y listo; IoCC hará el resto. No necesita proporcionar acceso global a su instancia de singleton porque el acceso ya está administrado por IoCC. Por lo tanto, no hay nada malo con IoC Singletons.

GoF Singletons en oposición a IoC Singletons se supone que exponen "singletonity" en la interfaz a través del método getInstance () y sufren de todo lo dicho anteriormente.

Volodymyr Frolov
fuente
3
En mi opinión, "singletonity" es un detalle del entorno de tiempo de ejecución, y no debe ser considerado por el programador que escribió el código de la clase. Más bien, es una consideración que debe realizar el USUARIO de la clase. solo el USUARIO sabe cuántas instancias se requieren realmente.
Earth Engine
5

Los singletons no son malvados, si los usas adecuadamente y mínimamente . Hay muchos otros buenos patrones de diseño que reemplazan las necesidades de singleton en algún momento (y también dan los mejores resultados). Pero algunos programadores desconocen esos buenos patrones y usan el singleton para todos los casos, lo que hace que el singleton sea malo para ellos.

Sriram
fuente
¡Increíble! ¡Completamente de acuerdo! Pero podrías, y quizás deberías, elaborar mucho más. Por ejemplo, expandir qué patrones de diseño se ignoran con mayor frecuencia y cómo usar "correctamente y mínimamente" los singletons. ¡Es más fácil decirlo que hacerlo ! : P
cregox
Básicamente, la alternativa es pasar objetos a través de parámetros de método, en lugar de acceder a ellos a través del estado global.
LegendLength
5

En primer lugar, una clase y sus colaboradores deben realizar primero su propósito previsto en lugar de centrarse en los dependientes. La gestión del ciclo de vida (cuando se crean instancias y cuando quedan fuera del alcance) no debe ser parte de la responsabilidad de las clases. La mejor práctica aceptada para esto es crear o configurar un nuevo componente para administrar dependencias mediante la inyección de dependencias.

A menudo, el software se vuelve más complicado, tiene sentido tener múltiples instancias independientes de la clase Singleton con un estado diferente. Confirmar código para simplemente tomar el singleton es incorrecto en tales casos. El uso Singleton.getInstance()puede estar bien para sistemas pequeños y simples, pero no funciona / escala cuando se necesita una instancia diferente de la misma clase.

Ninguna clase debería considerarse como un singleton, sino que debería ser una aplicación de su uso o de cómo se usa para configurar dependientes. Para que sea rápido y desagradable, esto no importa: solo la codificación dura dice que las rutas de archivos no importan, pero para aplicaciones más grandes, tales dependencias deben ser factorizadas y administradas de manera más apropiada usando DI.

Los problemas que el singleton causa en las pruebas es un síntoma de su caso / entorno de uso único codificado. El conjunto de pruebas y las muchas pruebas son individuales y separan algo que no es compatible con la codificación dura de un singleton.

mP.
fuente
4

Debido a que son básicamente variables globales orientadas a objetos, generalmente puede diseñar sus clases de tal manera que no las necesite.

Ycros
fuente
Si su clase no se limita a una sola instancia, necesitará miembros estáticos en su clase administrados por semáforos, ¡lo que resulta prácticamente lo mismo! ¿Cuál es su alternativa propuesta?
Jeach
Tengo una gran aplicación con una "Pantalla principal". Esta pantalla abre muchas ventanas modales / no modales / formularios de interfaz de usuario más pequeños. En mi humilde opinión, creo que MainScreen debe ser un singleton, por lo que, por ejemplo, un widget en algún lugar de la esquina de la aplicación quiere mostrar su estado en la barra de estado de MainScreen, todo lo que tiene que hacer es MainScreen.getInstance (). SetStatus ( "Algún texto"); ¿Qué propones como alternativa? ¿Pasar MainScreen por toda la aplicación? : D
Salvin Francis el
2
@SalvinFrancis: Lo que recomendaría es que dejes de tener objetos que se preocupan por cosas que no deberían importarles y te escabulles por la aplicación para jugar entre ellos. :) Su ejemplo sería mucho mejor hecho con eventos. Cuando realiza eventos correctamente, un widget ni siquiera tiene que preocuparse si hay una pantalla principal; solo transmite "hey, cosas sucedieron", y lo que sea que se haya suscrito al evento "cosas pasaron" (¡ya sea una pantalla principal, un WidgetTest o algo completamente diferente!) decide cómo quiere responder. Así es como se supone que debe hacerse OOP de todos modos. :)
cHao
1
@Salvin Considere lo difícil que es razonar sobre MainScreen cuando se depura si muchos componentes están actualizando 'silenciosamente'. Su ejemplo es una razón perfecta por la cual los singletons son malos.
LegendLength