Seamos sinceros. El patrón Singleton es un tema muy controvertido con los programadores de hordas en ambos lados de la cerca. Hay quienes sienten que el Singleton no es más que una variable global glorificada, y otros que juran por un patrón y lo usan incesantemente. Sin embargo, no quiero que la controversia Singleton esté en el centro de mi pregunta. Todo el mundo puede tener un tira y afloja y luchar y ver quién gana por lo que a mí respecta . Lo que estoy tratando de decir es que no creo que haya una sola respuesta correcta y no intento intencionalmente inflamar las disputas partidistas. Simplemente estoy interesado en alternativas de singleton cuando hago la pregunta:
¿Hay alguna alternativa específica al patrón GOF Singleton?
Por ejemplo, muchas veces cuando he usado el patrón singleton en el pasado, simplemente estoy interesado en preservar el estado / valores de una o varias variables. El estado / valores de las variables, sin embargo, se pueden conservar entre cada instanciación de la clase usando variables estáticas en lugar de usar el patrón singleton.
¿Qué otras ideas tienes?
EDITAR: Realmente no quiero que esta sea otra publicación sobre "cómo usar el singleton correctamente". Nuevamente, estoy buscando formas de evitarlo. Por diversión, ¿vale? Supongo que estoy haciendo una pregunta puramente académica con tu mejor voz de avance de película: "En un universo paralelo donde no hay singleton, ¿qué podríamos hacer?"
fuente
Respuestas:
Alex Miller en " Patrones que odio " cita lo siguiente:
"Cuando un singleton parece ser la respuesta, a menudo me parece más prudente:
fuente
Para comprender la forma correcta de solucionar los Singleton, debe comprender qué está mal con los Singleton (y el estado global en general):
Los singleton ocultan dependencias.
¿Por qué es tan importante?
Porque si oculta las dependencias, tiende a perder de vista la cantidad de acoplamiento.
Podrías argumentar que
es más simple que
pero al menos la segunda API deja en claro exactamente cuáles son los colaboradores del método.
Por lo tanto, la forma de solucionar los Singletons no es utilizar variables estáticas o localizadores de servicios, sino cambiar las clases Singleton en instancias, que se instancian en el ámbito donde tienen sentido y se inyectan en los componentes y métodos que los necesitan. Puede usar un marco de IoC para manejar esto, o puede hacerlo manualmente, pero lo importante es deshacerse de su estado global y hacer explícitas las dependencias y colaboraciones.
fuente
La mejor solución que he encontrado es usar el patrón de fábrica para construir instancias de sus clases. Al usar el patrón, puede asegurarse de que solo hay una instancia de una clase que se comparte entre los objetos que la usan.
Pensé que sería complicado de administrar, pero después de leer esta publicación de blog "¿Dónde se han ido todos los solteros?" , parece tan natural. Además, ayuda mucho a aislar las pruebas unitarias.
En resumen, ¿qué debes hacer? Siempre que un objeto depende de otro, recibirá una instancia de él solo a través de su constructor (no hay una palabra clave nueva en su clase).
Y luego, la fábrica.
Como solo creará una instancia de su fábrica, habrá una única instancia de exSingleton. Cada vez que llame a buildNeedy, la nueva instancia de NeedyClass se incluirá con exSingleton.
Espero que esto ayude. Señale cualquier error.
fuente
Spring o cualquier otro IoC-Container hace un trabajo razonablemente bueno en eso. Dado que las clases se crean y administran fuera de la aplicación, el contenedor puede hacer clases simples singletons e inyectarlas donde sea necesario.
fuente
No debería tener que salir de su camino para evitar cualquier patrón. El uso de un patrón es una decisión de diseño o un ajuste natural (simplemente encaja en su lugar). Cuando diseña un sistema, tiene la opción de usar un patrón o no usarlo. Sin embargo, no debe salir de su camino para evitar cualquier cosa que, en última instancia, sea una elección de diseño.
No evito el patrón Singleton. O es apropiado y lo uso o no es apropiado y no lo uso. Creo que es tan simple como eso.
La idoneidad (o falta de ella) del Singleton depende de la situación. Es una decisión de diseño que debe tomarse y las consecuencias de esa decisión deben entenderse (y documentarse).
fuente
Monostate (descrito en Agile Software Development de Robert C. Martin) es una alternativa al singleton. En este patrón, los datos de la clase son todos estáticos, pero los captadores / definidores no son estáticos.
Por ejemplo:
Monostate tiene un comportamiento similar al singleton, pero lo hace de una manera en la que el programador no es necesariamente consciente del hecho de que se está utilizando un singleton.
fuente
El patrón singleton existe porque hay situaciones en las que se necesita un solo objeto para proporcionar un conjunto de servicios .
Incluso si este es el caso, sigo considerando inapropiado el enfoque de crear singleton mediante el uso de un campo / propiedad estática global que representa la instancia. Es inapropiado porque crea una dependencia en el código entre el campo estático y el objeto, no los servicios que proporciona el objeto.
Entonces, en lugar del patrón clásico de singleton, recomiendo usar el patrón de servicio 'like' con contenedores con servicio , donde en lugar de usar su singleton a través de un campo estático, obtiene una referencia a él a través de un método que solicita el tipo de servicio requerido.
en lugar de un solo global
De esta manera, cuando desee cambiar el tipo de un objeto de singleton a otro, tendrá un tiempo fácil para hacerlo. Además, como beneficio adicional, no tiene que pasar una gran cantidad de instancias de objetos a cada método.
Consulte también Inversión de control , la idea es que al exponer los singleton directamente al consumidor, cree una dependencia entre el consumidor y la instancia del objeto, no los servicios de objeto proporcionados por el objeto.
Mi opinión es ocultar el uso del patrón singleton siempre que sea posible, porque no siempre es posible, o deseable, evitarlo.
fuente
Si está utilizando un Singleton para representar un único objeto de datos, podría pasar un objeto de datos como parámetro de método.
(aunque, en primer lugar, diría que esta es la forma incorrecta de usar un Singleton)
fuente
Si su problema es que desea mantener el estado, desea una clase MumbleManager. Antes de comenzar a trabajar con un sistema, su cliente crea un MumbleManager, donde Mumble es el nombre del sistema. El estado se conserva a través de eso. Lo más probable es que su MumbleManager contenga una bolsa de propiedades que contenga su estado.
Este tipo de estilo se siente muy parecido a C y no muy parecido a un objeto: encontrará que los objetos que definen su sistema tendrán todos una referencia al mismo MumbleManager.
fuente
Utilice un objeto simple y un objeto de fábrica. La fábrica es responsable de vigilar la instancia y los detalles del objeto simple solo con la información de configuración (que contiene, por ejemplo) y el comportamiento.
fuente
En realidad, si diseña desde cero para evitar Singeltons, es posible que no tenga que evitar no usar Singletons mediante el uso de variables estáticas. Cuando usas variables estáticas, también estás creando un Singleton más o menos, la única diferencia es que estás creando diferentes instancias de objetos, sin embargo internamente todos se comportan como si estuvieran usando un Singleton.
¿Puede dar un ejemplo detallado en el que utiliza un Singleton o donde se utiliza actualmente un Singleton y está tratando de evitar su uso? Esto podría ayudar a las personas a encontrar una solución más elegante de cómo se podría manejar la situación sin un Singleton.
Por cierto, personalmente no tengo problemas con Singletons y no puedo entender los problemas que tienen otras personas con respecto a Singletons. No veo nada malo en ellos. Es decir, si no está abusando de ellos. Se puede abusar de todas las técnicas útiles y, si se abusa, se producirán resultados negativos. Otra técnica que se utiliza habitualmente de forma incorrecta es la herencia. Aún así, nadie diría que la herencia es algo malo solo porque algunas personas abusan horriblemente de ella.
fuente
Personalmente, para mí, una forma mucho más sensata de implementar algo que se comporta como singleton es usar una clase completamente estática (miembros estáticos, métodos estáticos, propiedades estáticas). La mayoría de las veces lo implemento de esta manera (no puedo pensar en ninguna diferencia de comportamiento desde el punto de vista del usuario)
fuente
Creo que el mejor lugar para vigilar al singleton es el nivel de diseño de la clase. En esta etapa, debería poder trazar las interacciones entre clases y ver si algo absolutamente, definitivamente requiere que solo una instancia de esta clase exista en algún momento de la vida de la aplicación.
Si ese es el caso, entonces tienes un singleton. Si está lanzando singletons como una conveniencia durante la codificación, entonces realmente debería revisar su diseño y también dejar de codificar dichos singleton :)
Y sí, 'policía' es la palabra a la que me refería aquí en lugar de 'evitar'. El singleton no es algo que deba evitarse (de la misma manera que las variables goto y globales no son algo que deba evitarse). En su lugar, debe monitorear su uso y asegurarse de que sea el mejor método para hacer lo que desea de manera efectiva.
fuente
Utilizo singleton principalmente como "contenedor de métodos", sin ningún estado. Si necesito compartir estos métodos con muchas clases y quiero evitar la carga de la creación de instancias e inicialización, creo un contexto / sesión e inicializo todas las clases allí; todo lo que se refiere a la sesión también tiene acceso al "singleton" que contiene.
fuente
No habiendo programado en un entorno intensamente orientado a objetos (por ejemplo, Java), no estoy completamente al tanto de las complejidades de la discusión. Pero he implementado un singleton en PHP 4. Lo hice como una forma de crear un manejador de base de datos de 'caja negra' que se inicializaba automáticamente y no tenía que pasar llamadas de función arriba y abajo en un marco incompleto y algo roto.
Después de leer algunos enlaces de patrones singleton, no estoy completamente seguro de que lo implementaría de la misma manera nuevamente. Lo que realmente se necesitaba eran varios objetos con almacenamiento compartido (por ejemplo, el identificador de la base de datos real) y esto es más o menos en lo que se convirtió mi llamada.
Como la mayoría de los patrones y algoritmos, usar un singleton 'solo porque es genial' es lo incorrecto. Necesitaba una llamada verdaderamente de "caja negra" que se pareciera mucho a un singleton. Y en mi opinión, esa es la forma de abordar la pregunta: tenga en cuenta el patrón, pero también observe su alcance más amplio y en qué nivel su instancia debe ser única.
fuente
¿Qué quieres decir con cuáles son mis técnicas para evitarlo?
Para "evitarlo", eso implica que hay muchas situaciones con las que me encuentro en las que el patrón singleton encaja naturalmente bien y, por lo tanto, tengo que tomar algunas medidas para desactivar estas situaciones.
Pero no los hay. No tengo que evitar el patrón singleton. Simplemente no surge.
fuente