¿Es una mala idea crear una clase que solo tenga una instancia?

9

¿Es una mala práctica / diseño de codificación hacer una clase que solo se instanciará una vez?

Tengo algunas variables y funciones que se pueden agrupar bajo una clase para "verse bien" (a falta de una mejor descripción) ya que están algo relacionadas, pero pueden ser variables globales y funciones globales.

(Por cierto, estoy usando JavaScript, AngularJS, Express, MongoDB.)

Alicia
fuente
2
Quizás necesites una clase Singleton. Sin embargo, es una mala idea vincular en una clase cosas que no están relacionadas correctamente.
NeonGlow
2
El patrón Singleton es malo. Una sola instancia a veces es la solución correcta.
Bryan Chen el
44
Ni "Singleton" ni "Single instance" son una buena solución para agrupar cosas globales "solo un poco relacionadas". Cuando escucho tal descripción, siempre tomo esto como una señal de advertencia. Pero para darle una respuesta seria, debe decirnos algunos ejemplos de las variables y funciones que va a agrupar (con sus nombres y significado reales).
Doc Brown
2
El patrón Singleton no es necesariamente malo. Es solo que tiende a ser usado en exceso.
Stephen
¿Es técnicamente posible aplicar un Singleton en JavaScript?
Amy Blankenship

Respuestas:

10

Una instancia única para una clase tiene sentido si el objeto representa un recurso único, como una conexión de Ethernet o el administrador de tareas del sistema operativo, por ejemplo.

Las funciones se colocan en una clase solo si actúan sobre las variables de instancias de esa clase, de lo contrario el mantenedor se confundirá acerca de la intención de esa clase.

Por lo general, existe una buena razón por la cual su aplicación tiene variables globales. Intenta encontrar el propósito común de ellos y diseña una clase alrededor de este propósito. No solo aclarará el diseño, sino también su mente.

Mouviciel
fuente
2
+1, pero me gustaría agregar: "si el único propósito común es que esas variables son globales, es mejor dejarlas en diferentes clases".
Doc Brown
13

No hay problema con escribir una clase que termine siendo instanciada solo una vez.

Si reunir algunas variables y funciones dentro de una clase tiene sentido, tiene un valor semántico o hace que el código sea más fácil de leer y manipular, entonces que así sea, los mantenedores estarán agradecidos.

Sin embargo, lo que puede estar muy mal es hacer cumplir la unicidad desde adentro.

Muchas personas tienden a disparar el patrón singleton tan pronto como piensan que solo necesitarán una instancia de algo. Vea, por ejemplo, cómo no ha descrito su contexto en profundidad, pero la mayoría de las respuestas ya le sugieren que use un singleton. Y luego, el diseño podría estar atornillado porque si necesita otra instancia en algún momento por cualquier razón, la clase le impedirá hacerlo sin cambiar mucho código.

Como conclusión, una instancia está bien, pero asegúrese de saber si:

  1. que sólo necesita un ejemplo, o
  2. no puedes tener más de una instancia (un caso muy, muy raro en mi experiencia).
Julien Guertault
fuente
1
re: # 2, no creo que esto sea válido alguna vez. Incluso si su objeto es un NuclearPowerStationCentralCommandController y solo tendrá una central nuclear, no me está diciendo en serio que no tiene un MockNuclearPowerStationCentralCommandController para probar, ¿verdad?
Phoshi
Un problema más serio pero menos obvio es que si necesita una implementación ligeramente diferente del Singleton, no puede hacerlo en la mayoría de los idiomas, porque la forma de obtener el Singleton es ir directamente a él, en lugar de pasar la instancia .
Amy Blankenship
@Phoshi: Si solo puede existir uno de algo, entonces el código puede usarlo sin tener que contener una referencia. Si se permite que existan varias instancias, los consumidores deberán tener referencias a ellas. Esto no solo se suma al requisito de almacenamiento del objeto, sino que los consumidores ya no podrán asumir que otros consumidores tendrán una referencia al mismo objeto. Esto agrega considerable complejidad. Si la complejidad termina siendo necesaria, es mejor agregarla lo antes posible, pero si no es necesario, es mejor evitarla.
supercat
@supercat: Agregar el valor de uso de memoria de una referencia es completamente irrelevante para la abrumadora mayoría de los casos, no creo que sea una buena razón para evitar la DI. Tienes razón en que no puedes asumir que todos tienen la misma instancia, no deberías, eso no debería importar. No importa si todos tienen una instancia diferente siempre que se mantenga la semántica de la interfaz. De todos modos, como dije, nunca tendrás una sola instancia. Tiene al menos uno más para las pruebas, y ¿realmente quiere arriesgarse a asumir que sus requisitos nunca cambiarán?
Phoshi
@Phoshi: El uso de memoria no es el problema; El problema es que uno agrega otra forma en que los objetos pueden diferir. Considere, por ejemplo, lo que significa que los elementos en dos instancias Dictionary<TKey,KTValue>sean distintos. Si todas las instancias de una Dictionary<TKey,KTValue>instancia usan lo mismo IEqualityComparer, no hay ambigüedad, pero si pueden usar diferentes comparadores que definan diferentes relaciones de equivalencia, no sé si es posible definir a.ContentsDistinctFrom(b)con sensatez siempre igual b.ContentsDistinctFrom(a).
supercat
3

¿Es una mala práctica / diseño de codificación hacer una clase que solo se instanciará una vez?

No, incluso si solo se instancia una vez, necesita una clase para ello. Pero no suponga que siempre necesitará solo una instancia, ahora y en el futuro.

Supongamos que haces un juego y tienes una clase de jugador:

class Player {
    ...
}

Instanciará una clase de jugador en su juego y usará siempre el mismo objeto. No tiene nada de malo.

Sin embargo, ¡no hagas un Singleton! Hoy diseñas tu juego y piensas "Bueno, siempre será un juego de un jugador. Usaré un Singleton para mi jugador". Pero en la versión 2, es posible que desee implementar el modo multijugador, y luego se está metiendo en problemas. Tendrá que volver a escribir y adaptar una gran cantidad de código, porque su diseño no admite la creación de instancias de varios jugadores.

Lo mismo ocurre con los cachés. O madereros. O interfaces de red. Hoy, crees que solo necesitarás uno, siempre, seguro. Pero en una versión futura necesita agregar un segundo. Ten en cuenta esta situación.

Uooo
fuente
1

Hay clases singleton y ese es un patrón de diseño común.

También hay clases que nunca se instancian. Si tiene funciones que NO operan en ningún estado persistente (por ejemplo, toman la entrada y la transforman), generalmente puede usar un método estático. En algunos lenguajes (como Java), estos métodos estáticos se declararían en una clase, pero la clase en sí misma nunca se instanciará.

Uri
fuente
1

El patrón singleton es común. Le permite imponer una sola instancia de clase.

Pero para algunos es demasiado común, por lo que se convierte en un antipatrón. La razón de esto es porque es prácticamente lo mismo que el estado global. Y cualquier estado global es difícil de burlar y probar y difícil de depurar. Pero al mismo tiempo, tener que pasar explícitamente esta instancia a todas partes en su código puede hacer que el código se hinche mucho. Pero esto te hará pensar en una arquitectura adecuada. Si un montón de clases usan este singleton, puede pensar que están relacionados de alguna manera y crear un ancestro común para ellos, que encapsulará esta instancia para ellos.

Eufórico
fuente
1

Es malo asumir que algo es universalmente malo. En su caso, tal vez sería una buena idea, pero dado que está utilizando un lenguaje que no es OO en el núcleo, es más apropiado probablemente usar métodos y variables sueltos y colocarlos en una biblioteca común que incluya en su otro trabajo.

jwenting
fuente
1

Estás haciendo dos preguntas en una.

  1. No, no hay nada malo en tener una clase que solo tendrá una instancia.
  2. Agrupar variables y métodos en una clase sin una razón real es un mal diseño.
Tulains Córdova
fuente