Pregunta

La variable global glorificada - se convierte en una clase global glorificada. Algunos dicen romper el diseño orientado a objetos.

Dame escenarios, aparte del buen registrador antiguo donde tiene sentido usar el singleton.

¿Fue útil?

Solución

En mi búsqueda de la verdad, descubrí que en realidad hay muy pocos " aceptables " razones para usar un Singleton.

Una razón que tiende a aparecer una y otra vez en las redes internas es la de " registro " clase (que usted mencionó). En este caso, se puede usar un Singleton en lugar de una sola instancia de una clase porque, por lo general, una clase de registro debe usarse una y otra vez hasta el final por cada clase en un proyecto. Si todas las clases utilizan esta clase de registro, la inyección de dependencia se vuelve complicada.

El registro es un ejemplo específico de un " aceptable " Singleton porque no afecta la ejecución de tu código. Deshabilitar el registro, la ejecución del código sigue siendo el mismo. Habilitarlo, igual que Misko lo explica de la siguiente manera en Causa raíz de Singletons , " La información aquí fluye de una manera: desde su aplicación al registrador. A pesar de que los registradores se encuentran en un estado global, ya que no hay flujo de información desde los registradores a su aplicación, los registradores son aceptables. & Quot;

Estoy seguro de que también hay otras razones válidas. Alex Miller, en " Patterns I Hate " ;, las conversaciones sobre los localizadores de servicios y las IU del lado del cliente también son posiblemente aceptables " opciones.

Lee más en Singleton Te amo, pero me estás derrumbando.

Otros consejos

Un candidato de Singleton debe cumplir tres requisitos:

  • controla el acceso simultáneo a un recurso compartido.
  • el acceso al recurso se solicitará desde múltiples partes dispares del sistema.
  • solo puede haber un objeto.

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 impresora de 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.

Leer los archivos de configuración que solo deben leerse en el momento del inicio y encapsularlos en un Singleton.

Usted usa un singleton cuando necesita administrar un recurso compartido. Por ejemplo, una impresora de cola de impresión. Su aplicación solo debe tener una única instancia de la cola de impresión para evitar una solicitud conflictiva del mismo recurso.

O una conexión de base de datos o un administrador de archivos, etc.

Los singletons de solo lectura que almacenan algún estado global (idioma del usuario, ruta de acceso de la ayuda, ruta de la aplicación) son razonables. Tenga cuidado al usar singletons para controlar la lógica de negocios, ya que el single casi siempre es múltiple

Administrar una conexión (o un grupo de conexiones) a una base de datos.

También lo usaría para recuperar y almacenar información sobre archivos de configuración externos.

Una de las formas en que usas un singleton es para cubrir una instancia donde debe haber un solo " broker " Controlando el acceso a un recurso. Los Singleton son buenos en los registradores porque intermedian el acceso a, por ejemplo, un archivo, que solo se puede escribir exclusivamente. Para algo como el registro, proporcionan una forma de abstraer las escrituras a algo como un archivo de registro: puede envolver un mecanismo de almacenamiento en caché para su singleton, etc ...

También piense en una situación en la que tenga una aplicación con muchas ventanas / subprocesos / etc, pero que necesite un único punto de comunicación. Una vez usé uno para controlar los trabajos que quería que lanzara mi aplicación. 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 un tipo de " servidor " clase ejecutándose dentro de su aplicación ... HTH

Se debe usar un singleton cuando se administra el acceso a un recurso compartido por toda la aplicación, y sería destructivo tener varias instancias de la misma clase. Asegurarse de que el acceso seguro a los subprocesos de recursos compartidos sea un buen ejemplo de dónde este tipo de patrón puede ser vital.

Al usar Singletons, debe asegurarse de que no está ocultando accidentalmente las dependencias. Idealmente, los singletons (como la mayoría de las variables estáticas en una aplicación) se configuran durante la ejecución de su código de inicialización para la aplicación (estático vacío principal () para los ejecutables de C #, estático vacío válido () para los ejecutables de Java) y luego se pasan a Todas las demás clases que son instanciadas que lo requieren. Esto te ayuda a mantener la capacidad de prueba.

Puede encontrar un ejemplo práctico de un singleton en Test :: Builder , la clase que respalda casi todos los módulos modernos de pruebas de Perl. The Test :: Builder singleton almacena y negocia el estado y el historial del proceso de prueba (los resultados de las pruebas históricas cuentan el número de pruebas ejecutadas), así como los aspectos a los que se dirige la salida de la prueba. Todos estos son necesarios para coordinar varios 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 a new () siempre te da el mismo objeto. Primero, todos los datos se almacenaron como variables de clase sin nada en el objeto en sí. Esto funcionó hasta que quise probar Test :: Builder consigo mismo. Luego necesitaba dos objetos Test :: Builder, uno de configuración como un dummy, para capturar y probar su comportamiento y salida, y uno para ser el objeto de prueba real. En ese punto, Test :: Builder fue refactorizado en un objeto real. El objeto singleton se almacenó como datos de clase, y new () siempre lo devolvería. Se agregó create () para crear un objeto nuevo y habilitar las pruebas.

Actualmente, los usuarios desean cambiar algunos comportamientos de Test :: Builder en su propio módulo, pero dejan a otros solos, 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 monolítico Test :: Builder se está dividiendo en partes más pequeñas (historia, salida, formato ...) con una instancia de Test :: Builder que las recopila. Ahora Test :: Builder ya no tiene que ser un singleton. Sus componentes, como la historia, pueden ser. Esto empuja la inflexible necesidad de un singleton a un nivel. 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 de Test :: Builder se reproduzca utilizando el historial de Test :: Builder y los singletons de salida.

Parece que hay un impulso entre la coordinación de datos y la flexibilidad de comportamiento que puede mitigarse poniendo el singleton alrededor de los datos compartidos con la menor cantidad de comportamiento posible para garantizar la integridad de los datos.

Cuando carga un objeto de propiedades de configuración, ya sea desde la base de datos o desde un archivo, es útil tenerlo como un singleton; no hay razón para seguir releyendo los datos estáticos que no cambiarán mientras el servidor se esté ejecutando.

Creo que el uso de singleton se puede considerar como la relación 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.

Como todos han dicho, un recurso compartido, específicamente algo que no puede manejar el acceso simultáneo.

Un ejemplo específico que he visto es un escritor de índice de búsqueda de Lucene.

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 usan a lo largo del código.

Es un verdadero uso de objetos - > la clase de plantilla contiene la plantilla de página que se está construyendo, y se configura, agrega y modifica por los módulos que se agregan a la salida de la página. Debe mantenerse como una sola instancia para que esto pueda suceder, y lo mismo ocurre con las bases de datos. Con una base de datos compartida singleton, todas las clases de los módulos pueden obtener acceso a las consultas y obtenerlas sin tener que volver a ejecutarlas.

Un singleton de depósito de variable global le proporciona un depósito de variable global, confiable y fácil de usar. Se pone en orden mucho su 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'cons

Al final de ejecutar el código de la página, obtienes, digamos, un ya maduro:

$ template

Singleton, un singleton $ gb 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 la página del objeto de plantilla madura y luego se lo entregan al usuario.

La gran ventaja de esto es que puedes hacer CUALQUIER procesamiento posterior que quieras 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.

Puede usar Singleton cuando implemente el patrón de estado (de la manera que se muestra en el libro de GoF). Esto se debe a que las clases estatales concretas no tienen un estado propio y realizan sus acciones en términos de una clase de contexto.

También puedes hacer que Abstract Factory sea un singleton.

Puede ser muy pragmático configurar preocupaciones específicas de infraestructura como singletons o variables globales. Mi ejemplo favorito de esto son los marcos de inyección de dependencias que utilizan singletons para actuar como un punto de conexión con el marco.

En este caso, está tomando una dependencia de la infraestructura para simplificar el uso de la biblioteca y evitar una complejidad innecesaria.

Lo uso para un objeto que encapsula parámetros de línea de comandos cuando trato con 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 no siempre sabe qué módulos se están cargando). por ejemplo, las cargas principales A, que no necesitan ningún parámetro en sí (entonces, ¿por qué debería tomar un puntero / referencia / lo que sea, no estoy seguro? parece polución), luego carga los módulos X, Y y Z. Dos de estos, digamos X y Z, necesitan (o aceptan) los parámetros, por lo que vuelven a llamar al singleton de la línea de comandos para decirle qué parámetros deben aceptar, y en el tiempo de ejecución vuelven a llamar para averiguar si el usuario realmente ha especificado alguno de ellos.

De muchas maneras, un singleton para manejar los parámetros CGI funcionaría de manera similar si solo está usando un proceso por consulta (otros métodos mod_ * no lo hacen, por lo que sería malo allí, por lo tanto, el argumento que dice no debe usar singletons en el mundo mod_cgi en caso de que se transfiera a mod_perl o cualquier otro mundo).

Un ejemplo con código, quizás.

Aquí, ConcreteRegistry es un juego único en un juego de póker que permite que los comportamientos suban por el árbol de paquetes a las pocas interfaces centrales del juego (es decir, las fachadas para el modelo, la vista, el controlador, el entorno, etc.) .):

http://www.edmundkirwan.com/servlet/fractal /cs1/frac-cs40.html

Ed.

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 de unidad. Una clase estática no puede ser reemplazada por una prueba doble. Si no realiza la prueba de unidad, 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 protección de dependencias (Spring.NET, Unity para .NET, Spring para Java) o algún otro.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top