language agnostic - Los ejemplos más comunes de uso indebido de la clase de singleton
language-agnostic design-patterns (11)
A veces, asumes que solo habrá una cosa, entonces te equivocas.
Ejemplo, una clase de base de datos. Usted supone que solo se conectará a la base de datos de su aplicación.
// Its our database! We''ll never need another
class Database
{
};
¡Pero espera! Su jefe dice, enganche a la base de datos de otros muchachos. Digamos que desea agregar phpbb al sitio web y desea insertar su base de datos para integrar algunas de sus funcionalidades. ¿Deberíamos crear un nuevo singleton u otra instancia de base de datos? La mayoría de las personas está de acuerdo en que se prefiere una nueva instancia de la misma clase, no hay duplicación de código.
Prefieres tener
Database ourDb;
Database otherDb;
que copiar la base de datos y hacer:
// Copy-pasted from our home-grown database.
class OtherGuysDatabase
{
};
La pendiente resbaladiza aquí es que puede dejar de pensar en hacer una nueva instancia de clases y en su lugar comenzar a pensar que está bien tener un tipo por cada instancia.
¿Cuándo NO deberías utilizar una clase singleton, aunque podría ser muy tentador hacerlo? Sería muy bueno si tuviéramos una lista de las instancias más comunes de "singletonitis" que deberíamos evitar.
Bueno, los singletons en su mayor parte están haciendo las cosas estáticas de todos modos. Entonces, o bien estás haciendo que los datos sean globales, y todos sabemos que las variables globales son malas o estás escribiendo métodos estáticos y eso no es muy OO, ¿verdad?
Aquí hay una diatriba más detallada sobre por qué los singletons son malos, por Steve Yegge. Básicamente, no debe usar singletons en casi todos los casos, realmente no puede saber que nunca va a ser necesario en más de un lugar.
Cuando tiene múltiples aplicaciones ejecutándose en la misma JVM.
Un singleton es un singleton en toda la JVM, no solo una sola aplicación. Incluso si varios subprocesos o aplicaciones parecen estar creando un nuevo objeto singleton, todos usan el mismo si se ejecutan en la misma JVM.
En el caso de una conexión (por ejemplo), tiene sentido que no desee hacer que la conexión en sí misma sea única, puede necesitar cuatro conexiones, o puede necesitar destruir y volver a crear la conexión varias veces.
¿Pero por qué no accedería a todas sus conexiones a través de una única interfaz (es decir, administrador de conexión)?
Intento tener solo un singleton: una inversión de control / objeto de localización de servicio.
IService service = IoC.GetImplementationOf<IService>();
Los singleton son casi siempre una mala idea y generalmente inútiles / redundantes, ya que son solo una simplificación muy limitada de un patrón decente.
Mira cómo funciona la Inyección de Dependencia. Resuelve los mismos problemas, pero de una manera mucho más útil: de hecho, descubres que se aplica a muchas más partes de tu diseño.
Aunque puedes encontrar bibliotecas DI por ahí, también puedes rodar una básica, es bastante fácil.
No use un singleton para algo que pueda evolucionar en un recurso multiplable.
Esto probablemente suene tonto, pero si declaras algo como singleton, harás una declaración muy fuerte de que es absolutamente único. Estás construyendo código a su alrededor, más y más. Y cuando descubres después de miles de líneas de código que no es un singleton en absoluto, tienes una gran cantidad de trabajo delante de ti porque todos los demás objetos esperan que "el" objeto sagrado de la clase WizBang sea un singleton. .
Ejemplo típico: "Solo hay una conexión de base de datos que tiene esta aplicación, por lo tanto, es un singleton". - Mala idea. Es posible que desee tener varias conexiones en el futuro. Mejor crear un grupo de conexiones de base de datos y poblarlo con solo una instancia. Actúa como Singleton, pero el resto del código tendrá un código creíble para acceder al grupo.
EDITAR: entiendo que teóricamente puedes extender un singleton en varios objetos. Sin embargo, no existe un ciclo de vida real (como agrupar / desacoplar) lo que significa que no hay una propiedad real de los objetos que se han distribuido, es decir, el multiconexión múltiple ahora tendría que ser apátrida para ser utilizado simultáneamente por diferentes métodos e hilos.
Soy culpable de uno grande hace unos años (afortunadamente aprendí mi lesión desde entonces).
Lo que sucedió es que entré en un proyecto de aplicación de escritorio que se había convertido a .Net de VB6, y era un verdadero desastre. Cosas como funciones de 40 páginas (impresas) y ninguna estructura de clase real. Construí una clase para encapsular el acceso a la base de datos. No es un nivel de datos real (todavía), solo una clase base que un nivel de datos real podría usar. En algún lugar tuve la brillante idea de hacer de esta clase un singleton. Funcionó bien durante un año más o menos, y luego tuvimos que crear una interfaz web para la aplicación también. El singleton terminó siendo un gran cuello de botella para la base de datos, ya que todos los usuarios de la web tenían que compartir la misma conexión. De nuevo ... lección aprendida.
En retrospectiva, probablemente fue la elección correcta por un tiempo, ya que obligó a los otros desarrolladores a ser más disciplinados sobre su uso y los hizo conscientes de problemas de alcance que anteriormente no eran un problema en el mundo de VB6. Pero debería haberlo cambiado después de unas semanas antes de que tuviéramos demasiada confianza.
Una de las cosas que tienden a convertirlo en una pesadilla es si contiene un estado global modificable . Trabajé en un proyecto donde Singletons se usaba por todas partes para cosas que deberían haberse resuelto de una manera completamente diferente (estrategias de paso, etc.). La "des-singletonificación" era en algunos casos una reescritura importante de partes del sistema. Yo diría que en la mayor parte de los casos en que las personas usan Singleton, es incorrecto porque, en primer lugar, se ve bien, pero se convierte en un problema especialmente en las pruebas.
Aquí está una diatriba de mi amigo Alex Miller ... No enumera exactamente "cuando NO debes usar un singleton", pero es una publicación exhaustiva y excelente, y argumenta que uno solo debería usar un singleton en casos excepcionales, si es que lo hace. .
Sé que muchos han respondido con "cuando tienes más de uno", etc.
Como el póster original quería una lista de casos en los que no debería usar Singletons (en lugar de la razón principal), hablaré con:
¡Siempre que lo estés usando porque no puedes usar un global!
La cantidad de veces que he tenido un ingeniero junior que ha usado un Singleton porque sabían que no aceptaba globales en las revisiones de código. ¡A menudo parecen sorprendidos cuando les señalo que lo único que hicieron fue reemplazar un modelo global con un patrón de Singleton y todavía tienen un aspecto global!