design patterns - que - ¿Qué tiene de malo el singleton?
ventajas y desventajas del patron de diseño singleton (30)
Singleton no se trata de una sola instancia!
A diferencia de otras respuestas, no quiero hablar de lo que está mal con Singletons, ¡sino mostrarte lo poderosas y asombrosas 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 un solo hilo para inicializar todas las dependencias de su singleton. - Problema : es difícil burlarse de los singletons.
Solución : Use el método Factory para simularse.
MyModel myModel = Factory.inject(MyModel.class);
Puede asignarMyModel
a la claseTestMyModel
que lo hereda, en todas partes, cuando se inyecteMyModel
, se leTestMyModel
TestMyModel. - Problema : Singletons puede causar puerros de memoria ya que nunca se desecharon
Solución : Bueno, ¡dispóngalos! Implemente una devolución de llamada en su aplicación para deshacerse de los singletons correctamente, debe eliminar los datos vinculados a ellos y finalmente: eliminarlos de la fábrica.
Como dije en el título, el singleton no se trata de una sola instancia.
- Singletons mejora la legibilidad : puede mirar a su clase y ver qué singleton inyectó para averiguar qué es su dependencia.
- Singletons mejora el mantenimiento : una vez que eliminó una dependencia de una clase, acaba de eliminar un poco de inyección de Singleton, no necesita ir a 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 algo sucede en su aplicación, y se necesita una larga cadena de devoluciones de llamadas, está desperdiciando memoria y rendimiento. Al usar Singleton, está reduciendo el nivel medio, y mejorar su rendimiento y uso de memoria ( evitando asignaciones de variables locales innecesarias).
El patrón de singleton es un miembro completamente pagado del libro de patrones de GoF , pero últimamente parece bastante huérfano por el mundo de los desarrolladores. Todavía utilizo muchos singletons, especialmente para las clases de fábrica , y aunque tienes que ser un poco cuidadoso con los temas de multihilo (como cualquier clase en realidad), no veo por qué son tan horribles.
El desbordamiento de pila, en particular, parece asumir que todos están de acuerdo en que Singletons es malo. ¿Por qué?
Por favor, respalde sus respuestas con " hechos, referencias o experiencia específica "
- Se utiliza fácilmente (ab) como variable global.
- Las clases que dependen de singletons son relativamente más difíciles de probar por unidad en forma aislada.
Algunos snobs codificadores los ven como simplemente un glorificado global. De la misma manera en 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 un esfuerzo extraordinario 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 global .
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 no es un patrón para envolver globales. El patrón de Singleton solo debe usarse para garantizar que una y solo una instancia de una clase dada exista durante el tiempo de ejecución.
La gente piensa que Singleton es malvado 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 utiliza para el propósito para el que fue diseñado, obtendrá beneficios extremos del patrón Singleton.
El patrón de singleton no es un problema en sí mismo. El problema es que a menudo las personas que desarrollan software con herramientas orientadas a objetos utilizan el patrón 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 de ayuda para cada pequeño uso.
Singletons también son un problema desde una perspectiva de prueba. Tienden a hacer que las pruebas unitarias aisladas sean difíciles de escribir. 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 de unidad.
En un entorno de recolección de basura, los singletons pueden convertirse rápidamente en un problema con respecto a la administración de la 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.
Me gustaría abordar los 4 puntos en la respuesta aceptada, espero que alguien pueda explicar por qué estoy equivocado.
¿Por qué es malo ocultar las dependencias en tu código? Ya hay docenas de dependencias ocultas (llamadas en tiempo de ejecución de C, llamadas a la API del sistema operativo, llamadas a funciones globales), y las dependencias de singleton son fáciles de encontrar (buscar por ejemplo ()).
"Hacer algo global para evitar transmitirlo es un olor de código". ¿Por qué no está pasando algo para evitar convertirlo en un olor de código único?
Si está pasando un objeto a través de 10 funciones en una pila de llamadas solo para evitar un singleton, ¿es tan bueno?
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é agregar esta "responsabilidad" específica a una clase es importante?
¿Por qué pasar un objeto a una clase hace que esté más estrechamente acoplado que usar ese objeto como un singleton desde dentro de la clase?
¿Por qué cambia la duración del estado? Los Singletons pueden crearse o destruirse manualmente, por lo que el control aún está allí, y puede hacer que la vida útil sea la misma que la vida útil de un objeto que no sea Singleton.
En cuanto a las pruebas unitarias:
- no todas las clases necesitan ser probadas por unidad
- no todas las clases que necesitan ser probadas en una unidad necesitan cambiar la implementación del singleton
- si necesitan ser probados por una unidad y necesitan cambiar la implementación, es fácil cambiar una clase de usar un singleton a pasar el singleton a través de la inyección de dependencia.
Mi respuesta sobre cómo los Singletons son malos es siempre, "son difíciles de hacer bien". Muchos de los componentes fundamentales de los idiomas son singletons (clases, funciones, espacios de nombres e incluso operadores), al igual que los componentes en otros aspectos de la informática (localhost, ruta predeterminada, sistema de archivos virtual, etc.), y no es por accidente. Si bien causan problemas y frustraciones de vez en cuando, también pueden hacer que muchas cosas funcionen mucho mejor.
Los dos mayores errores que veo son: tratarlo como un problema global y no definir el cierre de 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 global no proviene intrínsecamente de ser global, sino de cómo se usa. Lo mismo ocurre con Singletons. En realidad, más aún como "instancia única" en realidad no tiene por qué significar "accesible globalmente". 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, parecen acceder siempre 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 de los códigos ni siquiera deberían ser conscientes de que se trata de un Singleton (acoplamiento suelto, ¿verdad?). Si solo un pequeño fragmento de código accede al objeto como si fuera un objeto global, se deshacen muchos daños. Recomiendo imponerlo restringiendo el acceso a la función de instancia.
El contexto de Singleton también es muy 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 de Singleton. El hecho de que solo haya uno no significa que Singleton sea algo omnipotente "siempre fue y siempre será", ni es generalmente deseable (los objetos sin un principio y un final violan todo tipo de supuestos útiles en el código, y solo deben emplearse En las circunstancias más desesperadas.
Si evita esos errores, Singletons aún puede ser un PITA, pero 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 de creación y destrucción definidos y un ciclo de vida que dicta cuándo y cómo se invocan, y cuyo método de "instancia" tiene protección del 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 decimos que son un mal patrón de diseño.
Misko Hevery, de Google, tiene algunos artículos interesantes sobre exactamente este tema ...
Singletons are Pathological Liars tiene un ejemplo de prueba de unidad 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 lo hace para que sus objetos puedan obtener en secreto cosas que no están declaradas en sus API y, como resultado, Singletons convierte sus API en mentirosos patológicos.
Donde todos los Singletons se han ido señalan 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 de lo malo, dijo Singletons global en el primer artículo.
No es que los singletons en sí mismos sean malos, pero el patrón de diseño de GoF sí lo es. El único argumento realmente válido es que el patrón de diseño de GoF no se presta para las pruebas, especialmente si las pruebas se ejecutan en paralelo.
El uso de una única instancia de una clase es una construcción válida siempre que aplique los siguientes medios en el código:
Asegúrese de que la clase que se utilizará como singleton implementa una interfaz. Esto permite implementar stubs o simulacros utilizando la misma interfaz
Asegúrese de que el Singleton es seguro para subprocesos. Eso es un hecho.
El singleton debe ser de naturaleza simple y no demasiado complicado.
Durante el tiempo de ejecución de su aplicación, donde los singletons deben pasar a un objeto determinado, use una fábrica de clases que genere ese objeto y haga que la fábrica de clases pase la instancia de singleton a la clase que lo necesita.
Durante las pruebas y para garantizar un comportamiento determinista, cree la clase singleton como una instancia separada, ya sea como la propia clase real o como un apéndice / simulacro que implementa su comportamiento y páselo como corresponde a la clase que lo requiere. No utilice el factor de clase que crea ese objeto bajo prueba que necesita el singleton durante la prueba, ya que pasará su instancia global única, lo que anula el propósito.
Hemos utilizado Singletons en nuestras soluciones con un gran éxito que puede comprobarse, lo que garantiza un comportamiento determinista en las secuencias de prueba paralelas.
Parafraseado de Brian Button:
Generalmente se utilizan 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 transmitirlo es un olor de código .
Violan el principio de responsabilidad única : en virtud del hecho de que controlan su propia creación y ciclo de vida.
Ellos inherentemente hacen que el código sea estrechamente coupled . Esto hace que la falsificación de pruebas sea bastante difícil en muchos casos.
Llevan estado alrededor durante toda la vida de la aplicación. Otro éxito en las pruebas, ya que puede terminar con una situación en la que es necesario ordenar las pruebas, que es un gran no, no para pruebas de unidad. ¿Por qué? Porque cada prueba unitaria debe ser independiente de la otra.
Singletons resuelve un problema (y solo uno).
Contención de recursos.
Si tienes algún recurso que
( 1 ) solo puede tener una sola instancia, y
( 2 ) necesitas gestionar esa única instancia,
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 cerrar correctamente. Este es un ejemplo de un único recurso compartido que debe administrarse.
Es raro que necesites un singleton. La razón por la que son malos es que se sienten como un global y son miembros completamente pagados del libro GoF GoF .
Cuando crees que necesitas un global, probablemente estés cometiendo un terrible error de diseño.
Singletons también son malos cuando se trata de agrupación . 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 entre sí, cree un SingletonDao
guardar hilos:
public class SingletonDao {
// songleton''s static variable and getInstance() method etc. omitted
public void writeXYZ(...){
synchronized(...){
// some database writing operations...
}
}
}
Así que está seguro de que solo existe un singleton en su aplicación y que toda la base de datos pasa por este único SingletonDao
. Su entorno de producción ahora se ve así:
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:
Eso suena raro, pero ahora tienes muchos singletons en tu 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 hacer 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 exista exactamente una instancia de un singleton en su aplicación, especialmente cuando se trata de agrupación en clústeres.
Un singleton se implementa utilizando un método estático. Las personas que realizan pruebas de unidad 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 la inversión del patrón de control .
Una cosa bastante mala de los singletons es que no se pueden extender muy fácilmente. Básicamente, tienes que construir algún tipo de patrón de decorador o algo así si quieres cambiar su comportamiento. Además, si un día quiere 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 pasarlos a quien los necesite en lugar de que tengan acceso a ellos directamente ... De lo contrario, si alguna vez elige tener varias formas de hacer lo que singleton hace, 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 ... Piense en ello y considere si su uso en la situación dada es inapropiado o no ... Las reglas están hechas para romperse generalmente, y los patterns no se deben aplicar sin pensar sin pensar.
Ver Wikipedia Singleton_pattern
Algunas personas también lo consideran un antipatrón, ya que consideran que se utiliza en exceso, introduciendo limitaciones innecesarias en situaciones en las que no se requiere realmente una instancia única de una clase. [1] [2] [3] [4]
Referencias (solo referencias relevantes del artículo)
- ^ Alex Miller. Patrones que odio # 1: Singleton , julio de 2007
- ^ Scott Densmore. ¿Por qué los singletones son malos , mayo de 2004?
- ^ Steve Yegge. Singletons considerado estúpido , septiembre de 2004
- ^ JB Rainsberger, IBM. Usa tus singletons sabiamente , julio de 2001
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
- Inicialización perezosa es deseable
- El acceso global no está previsto de otro modo.
Si la propiedad de la instancia única, cuándo y cómo se produce la inicialización y el acceso global no son problemas, Singleton no es lo suficientemente interesante.
El monopolio es el diablo y los singletons con estado no legible / mutable son el problema "real" ...
Después de leer Singletons are Pathological Liars, tal como se sugiere en la respuesta de Jason, encontré este pequeño detalle que brinda el ejemplo mejor presentado de cómo los singletons a menudo se usan de manera incorrecta.
Global es malo porque:
- a. Causa conflicto de espacio de nombres.
- segundo. Expone el estado de manera injustificada.
Cuando se trata de Singletons
- a. La forma explícita de llamarlos OO, evita los conflictos, por lo que apunta a. no es un problema
- segundo. Singletons sin estado son (como fábricas) no son un problema. Los Singletons con estado pueden caer nuevamente en dos categorías, aquellas que son inmutables o que se escriben una vez y leen muchas (archivos de configuración / propiedad). Estos no son malos. Los Singletons mutables, que son los titulares de referencia, son los que usted habla.
En la última declaración se refiere al concepto del blog de ''los singletons 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 inicio igual al comienzo del juego.
- solo se presenta un conjunto de reglas para evitar confusiones
- Las reglas no pueden cambiar a lo largo del juego.
Ahora, para cualquiera que no haya jugado realmente con el monopolio, estas normas son ideales en el mejor de los casos. Una derrota en el monopolio es difícil de tragar porque, el monopolio tiene que ver con el dinero, si pierdes tienes que ver con esmero que el resto de los jugadores terminen el juego, y las pérdidas suelen ser rápidas y aplastantes. Por lo tanto, las reglas generalmente se retuercen en algún momento para servir el interés propio de algunos de los jugadores a expensas de los demás.
Así que estás jugando el monopolio con amigos Bob, Joe y Ed. Estás construyendo rápidamente tu imperio y consumiendo cuota de mercado a un ritmo exponencial. Tus oponentes se están debilitando y empiezas a oler la sangre (en sentido figurado). Su amigo Bob puso todo su dinero en la paralización de tantas propiedades de bajo valor como fue posible, pero no está recibiendo un alto retorno de la inversión como esperaba. Bob, como un golpe de mala suerte, aterriza en tu paseo marítimo y se elimina del juego.
Ahora el juego pasa de tirar dados amistosos a negocios serios. A Bob se le ha dado el ejemplo del fracaso y Joe y Ed no quieren terminar como "ese tipo". Entonces, siendo el jugador principal, de repente, conviértete en el enemigo. Joe y Ed comienzan a practicar intercambios debajo de la mesa, inyecciones de dinero detrás de la espalda, cambio de casa infravalorado y, por lo general, algo que te debilita como jugador hasta que uno de ellos sube a la cima.
Entonces, en lugar de que uno de ellos gane, el proceso comienza de nuevo. De repente, un conjunto finito de reglas se convierte en un blanco móvil y el juego se degenera en el tipo de interacciones sociales que constituirían la base de todo programa de televisión de realidad con altas calificaciones 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 el caos se produce 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 representara con precisión un singleton, el libro de reglas del monopolio sería un ejemplo de abuso.
¿Cómo se aplica esto a la programación?
Aparte de todos los problemas obvios de seguridad de subprocesos y sincronización que presentan los singletons mutables ... Si tiene un conjunto de datos, es capaz de 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 retroceder 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 base de datos de subprocesos retorcidos dentro de una aplicación. Después de haber trabajado directamente en el código, puedo dar fe de que fue lento (debido a todos los bloqueos de subprocesos necesarios para hacerlo seguro) 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 de una manera mucho más sólida / modo 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 debería conectarse en cascada a las propiedades / miembros del objeto también.
Aquí hay una cosa más acerca de 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 característica de su interfaz. El contenedor de inversión de control puede ocultar esta característica a los usuarios de la clase; solo necesita marcar su clase como un singleton (con @Singleton
anotación en Java por ejemplo) y eso es todo; IoCC hará el resto. No es necesario que proporcione 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.
Se supone que GoF Singletons en el lado opuesto a IoC Singletons expone "singletonity" en la interfaz a través del método getInstance (), y por lo tanto sufren todo lo dicho anteriormente.
Cuando escribe código usando singletons, por ejemplo, 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 singletes hacen que sea muy difícil moverse 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 puede simplificarse si los envuelve todos 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);
}
Debido a que básicamente son variables globales orientadas a objetos, generalmente puede diseñar sus clases de tal manera que no las necesite.
Los Singletons son malos desde un punto de vista purista.
Desde un punto de vista práctico, un singleton es un compromiso entre tiempo de desarrollo y complejidad .
Si sabes que tu aplicación no cambiará mucho, están muy bien para usar. Solo tenga en cuenta que es posible que necesite refactorizar las cosas si sus requisitos cambian de forma inesperada (lo cual está bastante bien en la mayoría de los casos).
Singletons a veces también complica la prueba de la unidad .
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.
Singleton es un patrón y puede ser usado o abusado como cualquier otra herramienta.
La parte mala de un singleton es generalmente el usuario (o debería decir el uso inadecuado de un singleton para cosas para las que no está diseñado). El mayor delincuente está usando un singleton como una variable global falsa.
Artículo reciente sobre este tema por Chris Reath en Coding Sin comentarios .
Nota: la codificación sin comentarios ya no es válida. Sin embargo, el artículo que está vinculado a ha sido clonado por otro usuario.
Demasiadas personas ponen objetos que no son seguros para subprocesos en un patrón de singleton. He visto ejemplos de un DataContext ( LINQ to SQL ) realizado en un patrón de singleton, a pesar del hecho de que el DataContext no es seguro para subprocesos y es simplemente un objeto de unidad de trabajo.
El problema con los singletons es el problema de un mayor alcance y, por lo tanto, de coupled . No se puede negar que hay algunas situaciones en las que 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 da el beneficio de las clases que dependen de la instancia para no darse cuenta del hecho de que hay una sola instancia. La vida útil del singleton se puede cambiar en el futuro. Una vez que encontré el ejemplo que encontré recientemente, fue un ajuste fácil de subprocesos simples a subprocesos múltiples.
FWIW, si se trata de un PIA cuando intenta probarlo por unidad, entonces se va a PIA cuando intenta depurar, corregir un error o mejorarlo.
En primer lugar, una clase y sus colaboradores deben realizar primero el propósito previsto en lugar de centrarse en los desoendentes. La gestión del ciclo de vida (cuando las instancias son creadas y cuando están fuera del alcance) no debe ser parte de la responsabilidad de los cladses. La mejor práctica aceptada para esto es crear o configurar un nuevo componente para administrar las 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 diferentes estados. El cometer código para simplemente tomar el singleton es incorrecto en tales casos. El uso de Singleton.getInstance () puede ser correcto para sistemas pequeños y sencillos, pero no funciona / escala cuando uno necesita una instancia diferente de la misma clase.
Ninguna clase debe considerarse como un singleton, sino que debe ser una aplicación de su uso o cómo se utiliza para configurar dependientes. Para un rápido y desagradable, esto no importa, solo la codificación de hardware dice que las rutas de los archivos no son importantes, pero para las aplicaciones más grandes, es necesario tener en cuenta estas dependencias y administrarlas de manera más apropiada utilizando DI.
Los problemas que causa Singleton en las pruebas son un síntoma de su entorno / caso de uso único y codificado. El conjunto de pruebas y las muchas pruebas son individuales y separan algo que no es compatible con la codificación de un singleton.
No voy a comentar sobre el argumento bueno / malo, pero no los he usado desde que llegó la Spring . El uso de la inyección de dependencia ha eliminado bastante de mis requisitos para singleton, servicelocators y fábricas. Considero que este es un entorno mucho más productivo y limpio, al menos para el tipo de trabajo que hago (aplicaciones web basadas en Java).
Singletons no son malos Solo es malo cuando haces algo globalmente único que no es globalmente único.
Sin embargo, hay "servicios de alcance de aplicación" (piense en un sistema de mensajería que hace que los componentes interactúen): este LLAMADAS para un singleton, una "MessageQueue" - clase que tiene un método "SendMessage (...)".
A continuación, puede hacer lo siguiente desde todo el lugar:
MessageQueue.Current.SendMessage (new MailArrivedMessage (...));
Y, por supuesto, hacer:
MessageQueue.Current.RegisterReceiver (this);
En las clases que implementan IMessageReceiver.
Un patrón surge cuando varias personas (o equipos) llegan a soluciones similares o idénticas. Mucha gente sigue usando singletons en su forma original o usando plantillas de fábrica (buena discusión en el diseño moderno de C ++ de Alexandrescu). La concurrencia y la dificultad en la gestión de la vida útil del objeto son los principales obstáculos, mientras que el primero se gestiona fácilmente como usted sugiere.
Como todas las opciones, Singleton tiene su parte justa de altibajos. Creo que se pueden usar con moderación, especialmente para los objetos que sobreviven a la vida útil de la aplicación. El hecho de que se parezcan (y probablemente sean) a los globales presumiblemente ha desencadenado a los puristas.