2009-06-19 21 views
47

Duplicar posible:
What is so bad about Singletons?¿Los Singleton son realmente tan malos?

Es comprensible que muchos patrones de diseño en algunos casos pueden ser objeto de abuso, y al igual que mamá siempre dijo: "Demasiado de algo bueno no es ¡siempre es bueno! "

Me estoy dando cuenta de que en estos días, estoy usando mucho los Singletons, y me preocupa que pueda estar abusando del patrón de diseño yo mismo, y correr dee por y más profundamente en un hábito de mala práctica.

Estamos desarrollando una aplicación Flex que tiene una estructura de datos jerárquica bastante grande guardada en la memoria mientras el usuario trabaja en ella. El usuario puede cargar, guardar, cambiar y actualizar los datos a pedido.

Esta información se centraliza mediante una clase Singleton, que agrega un par de ArrayCollections, Arrays, objetos de valor y algunas otras variables de miembros nativos expuestas a través de getters y setters.

Para obtener una referencia de nuestros datos desde cualquier lugar de la aplicación, hacemos todo el método de método Model.getInstance() que estoy seguro de que todos conocen. Esto garantiza que siempre tengamos en nuestras manos la misma copia de datos, ya que cuando diseñamos, dijimos que solo una vez se permite que exista instancia durante la vida útil de la aplicación.

Desde este repositorio de datos central, es fácil para nosotros, por ejemplo, despachar eventos cambiados de propiedad y puede tener múltiples componentes de UI que hacen referencia a los datos centrales, actualizar sus pantallas para reflejar los cambios de datos que se han producido.

Hasta ahora, este enfoque ha sido eficaz y comprobado muy práctico para nuestras circunstancias.

Estoy encontrando, sin embargo, que estoy un poco ansioso al crear nuevas clases. Preguntas como si una clase fuera un Singleton, o si más bien se administrase de otra manera, como por ejemplo usar una fábrica por ejemplo, a veces se vuelve un poco difícil, con un poco de incertidumbre.

¿Dónde dibujo la línea con singletons? ¿Hay una buena pauta para decidir cuándo usar Singletons y cuándo mantenerse alejado de ellos?

Además, ¿alguien puede recomendar un buen libro sobre patrones de diseño?

+1

Hay una serie de preguntas similares a esto, pero no estoy seguro si alguno de ellos podría considerarse "duplicados exactos" ... – Zifre

+0

3 personas que recomiendan el mismo libro en menos de 5 minutos deben ser un registro. Y una sugerencia :-) – Stu

+1

el problema, en cualquier caso, es el exceso (ab-use) – BlackTigerX

Respuesta

35

La clave para recordar es que los patrones de diseño son solo una herramienta para ayudarlo a comprender los conceptos abstractos. Una vez que tenga esa comprensión, restringirse específicamente a una "receta" de un libro no tiene sentido y perjudica su capacidad para escribir el código más apropiado para su propósito.

Dicho esto, leer libros como GoF le presentará más formas de pensar en problemas para que cuando llegue el momento de implementar algo por su cuenta, tenga un conjunto más amplio de perspectivas para abordar el problema.

En su caso, si usar singleton tiene sentido en todos los casos, continúe adelante.Si se adapta "de alguna manera" y tienes que implementarlo de una manera un tanto torpe, entonces necesitas encontrar una nueva solución. Obligar a un patrón que no es perfecto es como martillar una clavija cuadrada en un agujero redondo.

Dado que usted dice "este enfoque ha sido eficaz y ha demostrado ser muy práctico para nuestras circunstancias", creo que lo está haciendo bien.

Éstos son algunos buenos libros:

Gang of Four Book - el libro clásico de los patrones de diseño

Head First Design Patterns - He oído esta recomendado por algunas personas como una alternativa

+0

¡¡¡Muchas gracias a todos !!! Definitivamente voy a obtener una copia de todos estos libros, y me abriré camino a través de ellos. Creo que escuché sobre el "Gang of Four Book" en alguna parte. –

+8

La mayor parte del resto del libro de GoF está bien, pero sobre el tema de los singletons, creo seriamente que deben haber estado fumando algo ilegal. O eso, o fue una concesión a viejos programadores de procedimientos (que realmente quieren sus globales), para ganarlos para OOP ("¡Oye, también puedes hacer globales en OOP! Simplemente los llamamos singletons") – jalf

+1

Sí Voy a decir lo que dice jalf, ten cuidado con el uso de singletons como solo una versión oop de las variables globales. –

0

No, no son necesariamente malas.

En cuanto a un libro, debe comenzar con el classics.

0

Singleton no se transmiten "que malo". Si tiene muchos Singletons relacionados y puede reemplazarlos/consolidarlos usando Factory, sin perder nada que le importe, entonces es cuando debería hacerlo.

En cuanto a libros, well, there's kind of a canon.

9

Los Singletons no matan a los programas, los programadores matan los programas.

Como cualquier construcción de programación, cuando se usa apropiadamente, no se disparará en el pie.

Los libros recomendados están bien, pero no siempre brindan suficientes antecedentes que incluyen la experiencia sobre cuándo se puede elegir usar Singleton.

Esa experiencia solo llega cuando ha encontrado que Singleton es una mala elección cuando necesita tener varias instancias, y de repente, tiene muchos problemas para inyectar las referencias de objetos en todas partes.

A veces es mejor seguir adelante y tener las referencias de los objetos en su lugar, pero el hecho de que esté usando Singleton ayuda a identificar el alcance del problema que enfrentaría si tuviera que refactorizarlo a un diseño diferente . Lo cual creo que es algo muy bueno: es decir, simplemente tener una clase en absoluto (incluso si está mal diseñado) le da cierta capacidad para ver los efectos de un cambio en la clase.

2

Los singletons ciertamente no son malos. Tienen sus usos, algunos de ellos muy buenos. Los singleton tienden a ser utilizados en exceso por los desarrolladores inexpertos, ya que a menudo es el primer patrón de diseño que aprenden, y es bastante simple, por lo que lo tiran por todos lados sin pensar en las implicaciones.

Cada vez que desee utilizar un singleton, intente considerar por qué lo hace y cuáles son los beneficios y los aspectos negativos de usar este patrón.

Los Singletons efectivamente crean un conjunto global accesible de 'cosas' (ya sea datos o métodos) y creo que la mayoría de la gente estaría de acuerdo en que usar demasiadas variables globales no es una gran idea. El objetivo de las clases y la orientación de los objetos es agrupar las cosas en áreas discretas en lugar de simplemente colocar todo en un espacio global masivo.

Uno de los 'patrones' que encuentro que prefiero sobre los singletons es pasar los objetos necesarios desde la parte superior. Los creo una vez durante la fase de inicialización de mi aplicación y los paso por todos los objetos que necesitan acceso a ellos. Imita la parte de 'creación única' de un patrón singleton, pero sin la parte 'global'.

El objetivo de un singleton es que sea para objetos donde solo 1 debería existir. Usted menciona un conjunto de clases de control de datos. Tal vez tenga en cuenta que, en realidad, hay casos en los que una aplicación podría querer crear 2 conjuntos de clases de control de datos, por lo que quizás aplicar un Singleton no sea del todo correcto. En cambio, si creó estas clases de datos en la aplicación init, y las pasó, solo estaría creando 1 conjunto, ya que eso es lo que necesita la aplicación actual, pero deja abierta la posibilidad de que en algún momento, si necesita un segundo conjunto puedes crearlos fácilmente. Además, las clases de control de datos deberían ser accesible globalmente desde cualquier lugar de la aplicación. Creo que no, en su lugar, probablemente solo deberían ser accesibles desde una capa de acceso a datos de nivel inferior.

Algunas personas han recomendado el libro de GOF. Yo diría que sí, que es un gran libro, pero primero intente primero encontrar un libro sobre arquitectura general, primero lea sobre diseño de 2/3/n-tier, encapsulación, abstracción y este tipo de principios. Esto le dará una base más sólida con la cual entender el uso apropiado de los patrones de los que GOF habla.

[Editar: La otra vez que una variante de singleton puede ser útil es cuando desea un punto de acceso único a algo, pero los detalles de la implementación en realidad podrían ser más de una cosa. La persona que llama no necesita saber que, bajo las cubiertas, su solicitud del objeto singleton se resuelve realmente contra varios objetos disponibles y se devuelve uno. Estoy pensando en algo así como un grupo de subprocesos aquí, donde va el uso, hey, solo dame un hilo, necesito 1, pero no me importa cuál]

+1

El grupo de subprocesos es un gran ejemplo de fallo de disparo de singleton. El grupo de subprocesos de .NET funciona así, y es un problema. Significa que no puedo crear un grupo de subprocesos para tareas en mi aplicación. Tengo que compartirlo con la biblioteca de clases .NET, con las librerías de terceros que pueda estar usando, y quién sabe qué más. No tengo forma de saber qué tan probable es * tener * un hilo libre. Un diseño sensato sería crear una clase de grupo de subprocesos que * cualquiera * pueda instanciar si quiere su * grupo de subprocesos * propio, y luego exponer un solo grupo de subprocesos global que podamos usar cuando no nos importa cuántos otros usuarios existan. – jalf

+0

@jaif: Siento que te has perdido el punto del hilo. Está ahí para tareas sucias muy simples y rápidas que quieras hacer fuera del hilo principal, si te interesa obtener un hilo libre o si quieres más control puedes usar la clase Thread o BackgroundWorker. Si desea su grupo de subprocesos administrados por usuarios personales, puede ver implementar un patrón productor-consumidor (vea la mitad de esta página: http://www.albahari.com/threading/part4.aspx). El objetivo de todo el grupo de subprocesos es equilibrar el trabajo asincrónico en todo el sistema, no solo en su aplicación. –

+3

¿Por qué debería * I * implementar este patrón yo mismo, cuando .NET ya intentó hacerlo por mí? El punto es que si no lo hubieran codificado como singleton, habría hecho el trabajo en todo el sistema que no lo hace, * además * para ser útil en ámbitos más pequeños dentro de mi propia aplicación. Es un ejemplo perfecto de singletons que eliminan la flexibilidad sin ningún motivo. No me estoy perdiendo el objetivo del grupo de subprocesos, digo que con una pequeña modificación, hubiera sido mucho más útil en general. – jalf

106

Sí, los singletons son malos. Son malas porque todo lo que hacen por ti es combinar dos propiedades, cada una de las cuales es mala aproximadamente el 95% del tiempo. (Lo que significaría que, en promedio, únicos son malos 99,75% de las veces;))

un producto único, tal como se define por el GoF, es una estructura de datos que:

  1. Subvenciones acceso global a un objeto y
  2. Implica que solo una instancia del objeto puede existir alguna vez.

El primero generalmente se considera una mala cosa. No nos gustan los globals. El segundo es un poco más sutil, pero, en general, prácticamente no hay casos en que esta sea una restricción razonable para hacer cumplir.

A veces, solo tiene sentido tener una instancia de un objeto. En cuyo caso, elige crear solo uno. No necesita un singleton para aplicarlo.

Y generalmente, incluso cuando "tiene sentido" tener solo una instancia, resulta que no tiene sentido después de todo. Tarde o temprano, vas a necesitar más de un registrador. O más de una base de datos. O tendrá que volver a crear recursos para cada una de las pruebas de su unidad, lo que significa que debemos poder crearlos a voluntad. Se elimina prematuramente la flexibilidad de nuestro código, antes de que comprendamos las consecuencias.

Singletons ocultan dependencias y aumentan el acoplamiento (cada clase puede depender de un singleton, lo que significa que la clase no puede reutilizarse en otros proyectos a menos que también reutilicemos todos nuestros singletons) y porque estas dependencias no son visibles inmediatamente (como parámetros de función/constructor), no los notamos, y normalmente no pensamos en eso cuando los creamos. Es tan fácil simplemente conectar un singleton, actúa casi como una variable local y todo, por lo que tendemos a usarlos mucho una vez que están allí. Y eso los hace casi imposibles de eliminar nuevamente. Terminas, tal vez no con el código de spaghetti, pero con gráficos de dependencia de espagueti.Y tarde o temprano, sus dependencias desbocadas significarán que los singletons comenzarán dependiendo de los demás, y luego obtendrán dependencias circulares cuando se intente inicializar.

Hacen extremadamente difícil la prueba de la unidad. (¿Cómo se prueba una función que llama a funciones en un objeto Singleton? No queremos que el código de producto único real que se ejerce, pero ¿cómo podemos evitar eso?

Sí, hijos únicos son malos.

veces , realmente quiere un global. Luego use un global, no un singleton.

A veces, muy, muy raramente, puede tener una situación donde crear una instancia múltiple de una clase es un error, donde puede no hecho sin causar errores. (Sobre el único caso en el que puedo pensar, e incluso eso es inventado, es si estás representando algún dispositivo de hardware. Solo tienes una GPU, así que si vas para asignarlo a un objeto en su código, tendría sentido que solo una instancia pueda existir). Pero si se encuentra en tal situación (y nuevamente, para enfatizar, una situación en la que varias instancias causan errores graves, no solo una situación en la que "no puedo pensar en ningún caso de uso para más de una instancia"), haga cumplir esa restricción, pero hazlo sin hacer también que el objeto sea visible globalmente.

Cada una de estas dos propiedades puede ser útil, en casos excepcionales. Pero no puedo pensar en un solo caso donde la combinación de ellos sería una buena cosa.

Desafortunadamente, muchas personas tienen la idea de que "Singletons son productos globales que cumplen con los requisitos de compatibilidad con OOP". No, no lo son. Todavía sufren los mismos problemas que los globales, además de para introducir algunos otros, sin relación alguna. No hay absolutamente ninguna razón para preferir un singleton sobre un simple viejo global.

+12

Hay un montón de veces en que la imposición de un singleton es una idea crítica. Piense en un grupo de conexión de base de datos. No querría dos grupos separados, ya que posiblemente abriría conexiones cuando ya haya algunas disponibles. – Kekoa

+44

¿Por qué no querría dos grupos separados en mis pruebas unitarias? ¿Por qué no querría dos grupos separados para bases de datos separadas? ¿Por qué no quiero dos grupos separados si tengo dos tareas separadas que no deberían permitirse matar de hambre mutuamente? Una tarea podría encerrar todas las conexiones en su propio grupo, así que quiero reservar algunas para el otro. Pero incluso si * desea * positivamente solo desea un grupo, ¿por qué necesita un singleton para aplicarlo? ¿Con frecuencia * accidentalmente * crea nuevos grupos de conexiones? Por supuesto no. Si solo necesitas uno, solo * crea * uno. – jalf

+3

+1 No podría haberlo dicho mejor. Exactamente cómo me siento y educo a mis colegas colegas. Muchos puntos también se aplican al patrón de monostate y (ab) al uso de métodos estáticos globales. – gix

0

Google parece ser convinced que Singletons es una mala idea.

Eso no quiere decir que todo lo que hace Google sea perfecto o que cada opinión sea el final de cualquier discusión, pero han llegado al extremo de escribir este detector Singleton para eliminarlos. Decídete de una vez.

3

En mi opinión, el uso de Singletons señala directamente un defecto de diseño. La razón es simplemente que permiten eludir los mecanismos normales de creación y destrucción de objetos integrados en C++. Si un objeto necesita una referencia a otro objeto, debe pasar una referencia a él en la construcción o crear una nueva instancia internamente. Pero cuando usas un singleton estás ocultando explícitamente el ciclo de creación y desmontaje. Un problema relacionado es que es extremadamente difícil controlar la vida útil de un singleton. Como resultado, muchos paquetes que incluyen implementaciones singleton genéricas también incluyen gestores de vida útil de objetos torpes y similares. A veces me pregunto si estos no existen simplemente para administrar los singletons.

Básicamente, si necesita usar un objeto en muchos lugares, debe crearse explícitamente en el punto común más alto de la pila y luego pasarlo por referencia a todos los que lo usen. A veces las personas usan Singletons porque tienen problemas para pasar múltiples argumentos a nuevos hilos, pero no se deje engañar por esto, defina explícitamente los argumentos de hilo y páselos al hilo nuevo de la misma manera. Descubrirá que su programa fluye mucho más limpio y no hay sorpresas desagradables debido a dependencias de inicialización estáticas o errores de desmontaje erróneos.

4

Hemos comenzado un proyecto donde básicamente nos enfrentamos a la misma pregunta, es decir, cómo acceder al modelo, y especialmente su elemento raíz.¡El proyecto no es una aplicación Flex, sino un juego! aplicación web, pero eso no importa realmente.

Tener un solo objeto única en el sistema está bien, el problema es cómo acceder a ella. Entonces, el debate sobre singleton está relacionado con la noción de inversión de dependencia (DI), y cómo obtener objetos.

los principales argumentos para DI son los siguientes:

  • la capacidad de prueba y burlarse
  • instanciación desacoplamiento objeto de uso (que puede conducir a la gestión del ciclo de vida)
  • separación de las preocupaciones

Posibles enfoques para DI son (vea el clásico article de Fowler):

  • para pasar objeto alrededor en Parámetros de métodos
  • localizador de servicios
  • marco DI

Bajo esta perspectiva, el patrón singleton es sólo un tipo de servicio de localización, por ejemplo, Model.getInstance().

Pero para proporcionar la máxima flexibilidad en la cara de los cambios futuros, la referencia al objeto único debe pasa alrededor tanto como sea posible, y obtenido con Model.getInstance() sólo cuando sea necesario. Esto también producirá un código más limpio.

+0

¿No termina con una gran cantidad de tuberías adicionales para ayudar a pasar las referencias? – kgriffs

+0

... especialmente para algo que prácticamente todos los componentes/clases van a usar, como el registro? – kgriffs

14

Los desarrolladores de software parecen estar bastante uniformemente dividido en dos campos, dependiendo de si están a favor de un estilo de codificación idealista o pragmática:

  • Idealista: Nunca utilizar el patrón Singleton.
  • Pragmatic: Evite el patrón singleton.

Personalmente, estoy a favor del enfoque pragmático. A veces tiene sentido romper las reglas, pero solo si realmente entiendes lo que estás haciendo y estás dispuesto a aceptar los riesgos asociados. Si puede responder "sí" a las preguntas siguientes con respecto a su caso de uso específico, el patrón de singleton puede generar algunos beneficios prácticos.

  • ¿Es el singleton externo a su aplicación? Las bases de datos, los servicios de puesta en cola y los ESB son todos ejemplos macro perfectamente válidos del patrón singleton.
  • BESO: ¿Está toda su aplicación limitada a 2-3 singleton internos?
  • DRY: ¿Son estos singleton inherentemente globales y, por lo tanto, tendrían que apuntar referencias en casi todos los objetos en su aplicación? (por ejemplo, un registrador o mediador de componentes)?
  • ¿Sus singletons dependen uno del otro y/o del entorno operativo?
  • ¿Se ha asegurado de que las secuencias de inicio y cierre sean las adecuadas para cada singleton, incluidas las consideraciones de administración de memoria?Por ejemplo, un grupo de subprocesos de estilo "Grand Central" puede necesitar métodos Run() y Shutdown() de instancia en main() para garantizar la ejecución de tareas solo cuando los objetos en los que operan están en un estado válido.
+1

Una buena manera de hacer que su adicción al singleton sea más socialmente aceptable. "Los evito, solo los uso donde tiene sentido". No, no lo haces. Según su propia descripción, los usa en cualquier lugar, en cualquier momento en que la alternativa requiera solo una pequeña cantidad de trabajo. La distinción no es entre "idealista" y "pragmático", sino entre aquellos que * realmente * intentan evitar singletons (no necesito * un singleton para la conexión de mi base de datos, por ejemplo), y aquellos que * dicen * "los evitan", cuando en realidad solo quieren decir "los uso cuando creo que es lo correcto" – jalf

2

Sé que este es un hilo antiguo, pero nadie parecía mencionar el patrón real que se ajusta a lo que el OP intentaba hacer. Lo que creo que está describiendo una necesidad se llama Mediator Pattern. SourceMaking es un sitio fantástico para aprender/hacer referencia a este tipo de información. Definitivamente voy al lugar para presentar a las personas los patrones del software. Además, generalmente es una buena idea no aceptar la idea de que cualquier patrón de diseño es inherentemente bueno o malo. Todos tienen su uso, solo aprender cuándo y dónde usarlos es el truco. Las personas que dicen que nunca deben usar Singletons, para mí, no entienden su utilidad.

Cuestiones relacionadas