La variable global glorificada se convierte en una clase global glorificada. Algunos dicen que rompe el diseño orientado a objetos.
Dame escenarios, además del buen viejo registrador donde tiene sentido usar el singleton.
design-patterns
singleton
Setori
fuente
fuente
Respuestas:
En mi búsqueda de la verdad descubrí que en realidad hay muy pocas razones "aceptables" para usar un Singleton.
Una razón que tiende a aparecer una y otra vez en Internet es la de una clase de "registro" (que usted mencionó). En este caso, se puede usar un Singleton en lugar de una sola instancia de una clase porque una clase de registro generalmente debe usarse una y otra vez hasta el cansancio por cada clase en un proyecto. Si cada clase usa esta clase de registro, la inyección de dependencia se vuelve engorrosa.
El registro es un ejemplo específico de un Singleton "aceptable" porque no afecta la ejecución de su código. Deshabilite el registro, la ejecución del código sigue siendo la misma. Habilítelo, lo mismo. Misko lo expresa de la siguiente manera en Causa raíz de Singletons : "La información aquí fluye de una manera: desde su aplicación al registrador. Aunque los registradores son de estado global, ya que no fluye información de los registradores a su aplicación, los registradores son aceptables".
Estoy seguro de que también hay otras razones válidas. Alex Miller, en " Patrones que odio ", habla de que los localizadores de servicios y la interfaz de usuario del lado del cliente también son opciones posiblemente "aceptables".
Lee más en Singleton Te amo, pero me estás deprimiendo.
fuente
Un candidato Singleton debe cumplir tres requisitos:
Si su Singleton propuesto tiene solo uno o dos de estos requisitos, un rediseño es casi siempre la opción correcta.
Por ejemplo, es poco probable que se llame a una cola de impresión desde más de un lugar (el menú Imprimir), por lo que puede usar mutexes para resolver el problema de acceso concurrente.
Un registrador simple es el ejemplo más obvio de un Singleton posiblemente válido, pero esto puede cambiar con esquemas de registro más complejos.
fuente
Lectura de archivos de configuración que solo deberían leerse en el momento del inicio y encapsulados en un Singleton
fuente
Properties.Settings.Default
en .NET.Utiliza un singleton cuando necesita administrar un recurso compartido. Por ejemplo, una cola de impresión. Su aplicación solo debe tener una única instancia de la cola de impresión para evitar solicitudes conflictivas para el mismo recurso.
O una conexión de base de datos o un administrador de archivos, etc.
fuente
Los singletons de solo lectura que almacenan algunos estados globales (lenguaje de usuario, ruta de ayuda, ruta de aplicación) son razonables. Tenga cuidado de usar singletons para controlar la lógica de negocios: el single casi siempre termina siendo múltiple
fuente
Administrar una conexión (o un grupo de conexiones) a una base de datos.
Lo usaría también para recuperar y almacenar información sobre archivos de configuración externos.
fuente
Una de las formas en que utiliza un singleton es para cubrir una instancia en la que debe haber un único "intermediario" que controle el acceso a un recurso. Los Singletons son buenos en los registradores porque brindan acceso a, digamos, un archivo, en el que solo se puede escribir exclusivamente. Para algo como el registro, proporcionan una forma de abstraer las escrituras a algo así como un archivo de registro: puede ajustar un mecanismo de almacenamiento en caché a su singleton, etc.
Piense también en una situación en la que tiene una aplicación con muchas ventanas / hilos / etc, pero que necesita un único punto de comunicación. Una vez usé uno para controlar los trabajos que quería que mi aplicación se iniciara. El singleton fue responsable de serializar los trabajos y mostrar su estado a cualquier otra parte del programa que estuviera interesado. En este tipo de escenario, puede ver un singleton como algo así como una clase de "servidor" que se ejecuta dentro de su aplicación ... HTH
fuente
Se debe usar un singleton al administrar el acceso a un recurso compartido por toda la aplicación, y sería destructivo tener múltiples instancias de la misma clase. Asegurarse de que el acceso a recursos compartidos sea seguro para subprocesos es un muy buen ejemplo de dónde este tipo de patrón puede ser vital.
Cuando use Singletons, debe asegurarse de no ocultar accidentalmente dependencias. Idealmente, los singletons (como la mayoría de las variables estáticas en una aplicación) se deben configurar durante la ejecución de su código de inicialización para la aplicación (static void Main () para ejecutables de C #, static void main () para ejecutables de java) y luego pasarlos a todas las demás clases que se crean instancias que lo requieren. Esto le ayuda a mantener la capacidad de prueba.
fuente
Creo que el uso único puede considerarse como la misma relación de muchos a uno en las bases de datos. Si tiene muchas partes diferentes de su código que necesitan trabajar con una sola instancia de un objeto, ahí es donde tiene sentido usar singletons.
fuente
Un ejemplo práctico de un singleton se puede encontrar en Test :: Builder , la clase que respalda casi todos los módulos de prueba modernos de Perl. Test :: Builder Singleton almacena y corre el estado y el historial del proceso de prueba (resultados históricos de la prueba, cuenta el número de pruebas ejecutadas), así como cosas como a dónde va la salida de la prueba. Todos estos son necesarios para coordinar múltiples módulos de prueba, escritos por diferentes autores, para trabajar juntos en un solo script de prueba.
La historia de Test :: Builder's singleton es educativa. Llamar
new()
siempre te da el mismo objeto. Primero, todos los datos se almacenaron como variables de clase sin nada en el objeto mismo. Esto funcionó hasta que quería probar Test :: Builder consigo mismo. Luego, necesitaba dos objetos Test :: Builder, uno configurado como un ficticio, para capturar y probar su comportamiento y salida, y uno para ser el objeto de prueba real. En ese momento, Test :: Builder se refactorizó en un objeto real. El objeto singleton se almacenó como datos de clase ynew()
siempre lo devolvería.create()
fue agregado para hacer un objeto nuevo y permitir la prueba.Actualmente, los usuarios desean cambiar algunos comportamientos de Test :: Builder en su propio módulo, pero dejan a otros en paz, mientras que el historial de pruebas permanece en común en todos los módulos de prueba. Lo que está sucediendo ahora es que el objeto Test :: Builder monolítico se está dividiendo en partes más pequeñas (historial, salida, formato ...) con una instancia de Test :: Builder reuniéndolos juntos. Ahora Test :: Builder ya no tiene que ser un singleton. Sus componentes, como la historia, pueden ser. Esto empuja la necesidad inflexible de un singleton por un nivel. Le da más flexibilidad al usuario para mezclar y combinar piezas. Los objetos singleton más pequeños ahora solo pueden almacenar datos, y sus objetos que contienen deciden cómo usarlos. Incluso permite que una clase que no sea Test :: Builder juegue utilizando el historial Test :: Builder y los singletons de salida.
Parece que hay un empuje y atracción entre la coordinación de datos y la flexibilidad de comportamiento que puede mitigarse colocando el singleton alrededor de los datos compartidos con la menor cantidad de comportamiento posible para garantizar la integridad de los datos.
fuente
Cuando carga un objeto Propiedades de configuración, ya sea desde la base de datos o un archivo, ayuda tenerlo como un singleton; no hay razón para seguir leyendo datos estáticos que no cambiarán mientras el servidor se esté ejecutando.
fuente
Como todos han dicho, un recurso compartido, específicamente algo que no puede manejar el acceso concurrente.
Un ejemplo específico que he visto es un escritor de índice de búsqueda de Lucene.
fuente
Puede usar Singleton al implementar el patrón de estado (de la manera que se muestra en el libro GoF). Esto se debe a que las clases de estado concretas no tienen un estado propio y realizan sus acciones en términos de una clase de contexto.
También puede hacer que Abstract Factory sea un singleton.
fuente
setState()
responsabilizarte para decidir la política de creación del estado. Ayuda si su lenguaje de programación admite plantillas o genéricos. En lugar de Singleton, podría usar el patrón Monostate , donde instanciar un objeto de estado termina reutilizando el mismo objeto de estado global / estático. La sintaxis para cambiar el estado podría permanecer sin cambios, ya que sus usuarios no necesitan saber que el estado instanciado es un Monostate.Recursos compartidos. Especialmente en PHP, una clase de base de datos, una clase de plantilla y una clase de depósito de variable global. Todos tienen que ser compartidos por todos los módulos / clases que se utilizan en todo el código.
Es un verdadero uso de objetos:> la clase de plantilla contiene la plantilla de página que se está creando, y los módulos que se agregan a la salida de la página le dan forma, agregan y cambian. Debe mantenerse como una única instancia para que esto pueda suceder, y lo mismo ocurre con las bases de datos. Con una base de datos compartida única, todas las clases de los módulos pueden acceder a las consultas y obtenerlas sin tener que volver a ejecutarlas.
Un depósito variable global singleton le proporciona un depósito variable global, confiable y fácil de usar. Limpia mucho tu código. Imagine tener todos los valores de configuración en una matriz en un singleton como:
$gb->config['hostname']
o tener todos los valores de idioma en una matriz como:
$gb->lang['ENTER_USER']
Al final de ejecutar el código de la página, obtienes, por ejemplo, un ahora maduro:
$template
Singleton, un
$gb
singleton que tiene la matriz lang para reemplazarlo, y toda la salida está cargada y lista. Simplemente reemplácelos en las claves que ahora están presentes en el valor de página del objeto de plantilla maduro y luego se lo entrega al usuario.La gran ventaja de esto es que puede hacer CUALQUIER procesamiento posterior que desee en cualquier cosa. Puede canalizar todos los valores de idioma a google translate u otro servicio de traducción y recuperarlos, y reemplazarlos en sus lugares, traducidos, por ejemplo. o, puede reemplazar en estructuras de página, o cadenas de contenido, como desee.
fuente
Puede ser muy pragmático configurar problemas específicos de infraestructura como singletons o variables globales. Mi ejemplo favorito de esto son los marcos de inyección de dependencia que hacen uso de singletons para actuar como un punto de conexión al marco.
En este caso, dependerá de la infraestructura para simplificar el uso de la biblioteca y evitar la complejidad innecesaria.
fuente
Lo uso para un objeto que encapsula los parámetros de la línea de comandos cuando se trata de módulos conectables. El programa principal no sabe cuáles son los parámetros de la línea de comandos para los módulos que se cargan (y ni siquiera sabe qué módulos se están cargando). p. ej., las cargas principales A, que no necesitan ningún parámetro en sí (entonces, por qué debería tomar un puntero / referencia adicional / lo que sea, no estoy seguro, parece contaminación), luego carga los módulos X, Y y Z. Dos de estos, digamos X y Z, necesitan (o aceptan) parámetros, por lo que vuelven a llamar a la línea de comando singleton para decirle qué parámetros aceptar, y en el tiempo de ejecución que llaman para averiguar si el usuario realmente ha especificado de ellos.
En muchos sentidos, un singleton para manejar parámetros CGI funcionaría de manera similar si solo usa un proceso por consulta (otros métodos mod_ * no hacen esto, por lo que sería malo allí, por lo tanto, el argumento que dice que no debería ' No use singletons en el mundo mod_cgi en caso de que se transfiera al mod_perl o cualquier otro mundo).
fuente
Un ejemplo con código, tal vez.
Aquí, ConcreteRegistry es un singleton en un juego de póker que permite que los comportamientos hasta el árbol del paquete accedan a las pocas interfaces principales del juego (es decir, las fachadas para el modelo, vista, controlador, entorno, etc.):
http://www.edmundkirwan.com/servlet/fractal/cs1/frac-cs40.html
Ed.
fuente
1 - Un comentario sobre la primera respuesta:
No estoy de acuerdo con una clase de registrador estático. Esto puede ser práctico para una implementación, pero no puede ser reemplazable para pruebas unitarias. Una clase estática no puede ser reemplazada por una prueba doble. Si no realiza una prueba unitaria, no verá el problema aquí.
2 - Intento no crear un singleton a mano. Simplemente creo un objeto simple con constructores que me permiten inyectar colaboradores en el objeto. Si necesitara un singleton, usaría un marco de inyección de dependencia (Spring.NET, Unity para .NET, Spring para Java), o algún otro.
fuente
ILogger logger = Logger.SingleInstance();
cuando este método es estático y devuelve una instancia estáticamente almacenada de un ILogger. Usó el ejemplo de "un marco de inyección de dependencias". Casi todos los contenedores DI son singletons; sus configuraciones se definen de forma estática y, en última instancia, se accede a ellas desde / almacenadas en una única interfaz de proveedor de servicios.