design-patterns - ejercicios - patron singleton php
Sobre patrones de diseño: ¿Cuándo debo usar el singleton? (18)
La variable global glorificada se convierte en una clase global glorificada. Algunos dicen romper el diseño orientado a objetos.
Dame escenarios, aparte del viejo y viejo registrador, en el que tiene sentido usar el singleton.
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 hace 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.
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.
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.
Creo que el uso de singleton se puede considerar como la 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.
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 datos estáticos que no cambiarán mientras el servidor esté en ejecución.
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 por lo general necesita ser usada 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 incómoda.
El registro es un ejemplo específico de un Singleton "aceptable" porque no afecta la ejecución de su 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 Root Cause of Singletons : "La información aquí fluye de una manera: desde su aplicación al registrador. Aunque los registradores están en estado global, ya que no hay información de los registradores hacia su aplicación, los registradores son aceptables".
Estoy seguro de que hay otras razones válidas también. Alex Miller, en " Patterns I Hate ", habla de que los localizadores de servicios y las IU del lado del cliente también son opciones posiblemente "aceptables".
Lectura de archivos de configuración que solo deben leerse en el momento del inicio y encapsulando en un Singleton.
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 tener un puntero / referencia / lo que sea más? 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) los parámetros, por lo que devuelven la llamada al singleton de la línea de comandos para decirle qué parámetros deben aceptar, y en el tiempo de ejecución devuelven la llamada 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 que no debería hacerlo) t use singletons en el mundo mod_cgi en caso de que se transfiera a mod_perl o cualquier otro mundo).
Los archivos de solo lectura que guardan 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: el single casi siempre termina siendo múltiple
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.
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.
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, se agrega, se modifica mediante 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 su código mucho. 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, obtiene, digamos, un singleton de $template
ahora maduro, un singleton de $gb
que tiene la matriz lang para reemplazarlo, y toda la salida está cargada y lista. Simplemente reemplácelas en las claves que ahora están presentes en el valor de la página del objeto de plantilla madura y luego se las entrega 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.
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 a los recursos compartidos sea seguro es un buen ejemplo de dónde este tipo de patrón puede ser vital.
Cuando use 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 le ayuda a mantener la capacidad de prueba.
Un candidato de Singleton debe cumplir tres requisitos:
- controla el acceso concurrente a un recurso compartido.
- el acceso al recurso se solicitará desde múltiples partes dispares del sistema.
- Sólo 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 un administrador 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.
Un ejemplo con código, tal vez.
Aquí, ConcreteRegistry es un juego único en un juego de póquer 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.
Un ejemplo práctico de un singleton se puede encontrar en Test::Builder , la clase que respalda casi todos los módulos de pruebas de Perl modernos. 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 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 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 necesité dos objetos Test :: Builder, uno de configuración como ficticio, 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 sigue siendo 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 (historial, 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 se puede mitigar poniendo el singleton alrededor de los datos compartidos con la menor cantidad posible de comportamiento para garantizar la integridad de los datos.
Una de las formas en que usa un singleton es cubrir una instancia en la que debe haber un solo "intermediario" que controle 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.
Piense también 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 utilicé 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 una clase de "servidor" que se ejecuta dentro de su aplicación ... HTH
Utiliza 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 la solicitud conflictiva del mismo recurso.
O una conexión de base de datos o un administrador de archivos, etc.