Solitario | |
---|---|
único | |
Tipo de | generando |
ventajas | organiza la API; carga implícitamente los módulos correctos en el orden correcto; deja espacio para un segundo objeto similar |
menos | complica las pruebas, los subprocesos múltiples y el seguimiento de latencia; los singletons no deben depender implícitamente unos de otros |
Descrito en Patrones de diseño | Sí |
Un singleton es un patrón de diseño generativo que garantiza que habrá una sola instancia de una determinada clase en una aplicación de un solo subproceso y proporciona un punto de acceso global a esta instancia.
La clase tiene solo una instancia y le proporciona un punto de acceso global. Cuando intenta crear este objeto , se crea solo si aún no existe; de lo contrario, se devuelve una referencia a una instancia ya existente y no se produce una nueva asignación de memoria. Es esencial que sea posible utilizar una instancia de la clase, ya que en muchos casos se dispone de una funcionalidad más amplia. Por ejemplo, se puede acceder a los componentes de clase descritos a través de la interfaz , si el idioma admite esa posibilidad.
A veces se necesita un objeto "solitario" global, es decir, un objeto ( ), y no un conjunto de procedimientos no asociados con ningún objeto ( ): log().put("Test");logPut("Test");
Dichos objetos también se pueden crear durante la inicialización del programa. Esto puede conducir a las siguientes dificultades:
Esta opción bloquea el método getInstance(), ya sea que hayamos creado una sola instancia o no. Esto ralentiza el programa si necesita obtener un objeto Singleton de diferentes subprocesos con frecuencia.
Singleton de clase pública { instancia de Singleton estática privada ; Singleton privado () {}; Singleton sincronizado estático público getInstance () { if ( instancia == nulo ) { instancia = new Singleton (); } instancia de retorno ; } }De PEP 0318 Archivado el 3 de junio de 2020 en Wayback Machine :
Ejemplo de Python con decoradores def singleton ( cls ): instancias = {} def getinstance (): si cls no está en instancias : instancias [ cls ] = cls () devuelve instancias [ cls ] devuelve getinstance @singleton clase MiClase : ...De PEP 0318 Archivado el 3 de junio de 2020 en Wayback Machine . :
Ejemplo de Python en MetaClasses clase MetaSingleton ( tipo ): _instances = {} def __call__ ( cls , * args , ** kwargs ): si cls no está en cls . _instancias : cls . _instances [ cls ] = super ( MetaSingleton , cls ) . __call__ ( * argumentos , ** kwargs ) devuelve cls . _instancias [ cls ] clase MiClase ( metaclase = MetaSingleton ): ...La siguiente es una posible implementación del patrón Singleton en C++ (conocido como el singleton de Myers ), donde el singleton es un objeto local estático. El punto importante es que el constructor de la clase se declara como private, lo que evita que se cree una instancia de la clase fuera de su implementación. Además, el constructor de copia y el operador de asignación también se declaran privados. Este último debe declararse, pero no definirse, ya que esto permite un error de vinculación fácilmente detectable si se llaman accidentalmente desde el código. Tenga en cuenta también que el ejemplo anterior no es seguro para subprocesos en C ++ 03, para trabajar con una clase de varios subprocesos, debe proteger la variable theSingleInstancedel acceso simultáneo, por ejemplo, utilizando un mutex o una sección crítica . Sin embargo, en C++11 , Myers singleton es seguro para subprocesos y no tiene bloqueos.
Ejemplo en C++ clase SoloUno { público : OnlyOne estático e instancia () { static OnlyOne theSingleInstance ; devuelve la instancia única ; } privado : SoloUno (){} OnlyOne ( const OnlyOne & root ) = eliminar ; SóloUno & operador = ( const SóloUno & ) = borrar ; };Otro ejemplo de implementación de un singleton en C++ con posibilidad de herencia para crear una interfaz, cuyo framework será, de hecho, un singleton. La vida útil de un solo objeto se controla convenientemente mediante el mecanismo de conteo de referencia .
Ejemplo en C++ clase Singleton { protegido : Singleton estático * _self ; Singleton () {} virtual ~ Singleton () {} público : Singleton estático * Instancia () { si ( ! _self ) { _self = nuevo Singleton (); } volver _self ; } bool estático DeleteInstance () { si ( _yo ) { borrar_yo ; _ _yo = 0 ; devolver verdadero ; } devolver falso ; } }; Singleton * Singleton :: _self = 0 ;Sin embargo, la forma más sencilla de implementar un singleton perezoso y seguro para subprocesos requiere la versión 4 o superior de .NET.
Singleton de clase pública sellada { private static readonly Lazy < Singleton > titular de instancia = new Lazy < Singleton >(() => new Singleton ()); singleton privado () { ... } Instancia Singleton pública estática { get { return instanceHolder . valor ; } } }Para la inicialización diferida de un Singleton en C#, se recomienda utilizar constructores de tipo (constructor estático). El CLR invoca automáticamente al constructor del tipo la primera vez que se accede al tipo, mientras mantiene la seguridad de la sincronización de subprocesos. El compilador genera automáticamente el constructor de tipos y todos los campos del tipo (campos estáticos) se inicializan en él. No debe establecer explícitamente el constructor de tipos, porque en este caso se llamará inmediatamente antes de que se llame al tipo y el compilador JIT no podrá aplicar la optimización (por ejemplo, si la primera llamada a Singleton ocurre en un bucle) .
/// Singleton<T> genérico (seguro para subprocesos usando clase genérica e inicialización diferida) /// <typeparam name="T">Clase Singleton</typeparam> public class Singleton < T > where T : class { /// El constructor protegido es necesario para evitar que se cree una instancia de la clase Singleton. /// Será llamado desde el constructor privado de la clase heredada. Singleton protegido () { } /// Se usa una fábrica para inicializar de forma diferida una instancia de clase clase privada sellada SingletonCreator < S > where S : class { // Usado por Reflection para instanciar una clase sin un constructor público private static readonly S instancia = ( S ) typeof ( S ). GetConstructor ( BindingFlags . Instance | BindingFlags . NonPublic , null , new Type [ 0 ], new ParameterModifier [ 0 ]). Invocar ( nulo ); public static S CreatorInstance { get { instancia de retorno ; } } } Instancia T estática pública { get { return SingletonCreator < T >. InstanciaCreador ; } } } /// Uso de la clase pública Singleton TestClass : Singleton < TestClass > { /// Llama al constructor protegido de la clase Singleton private TestClass () { } public string TestProc () { return "Hello World" ; } }También puede usar la implementación Singleton estándar segura para subprocesos de inicialización diferida:
public class Singleton { /// El constructor protected es necesario para evitar la creación de una instancia de la clase Singleton protected Singleton () { } SingletonCreator de clase privada sellada { instancia de Singleton de solo lectura estática privada = new Singleton (); Instancia Singleton estática pública { get { instancia de retorno ; } } } Instancia Singleton pública estática { get { return SingletonCreator . instancia ; } } }Si no hay necesidad de ningún método o propiedad estático público (aparte de la propiedad Instancia), se puede usar una versión simplificada:
Singleton de clase pública { instancia de Singleton de solo lectura estática privada = new Singleton (); Instancia Singleton estática pública { get { instancia de retorno ; } } /// Se necesita el constructor protected para evitar la creación de una instancia de la clase Singleton protected Singleton () { } }Ejemplo de inicialización diferida
espacio de nombres Singleton { clase pública Singleton { instancia privada estática de Singleton ; Instancia Singleton estática pública { obtener { instancia de retorno ?? ( instancia = nuevo Singleton ()); } } Singleton protegido () { } } }Para Delphi 2005 y superior, el siguiente ejemplo es adecuado (no seguro para subprocesos):
ejemplo de Delfos tipo TSingleton = clase estricta clase privada var Instancia : TSingleton ; función de clase pública NewInstance : TObject ; anular ; fin ; Función de clase TSingleton . NewInstance : TObject ; comenzar si no está asignado ( Instancia ) luego Instancia : = TSingleton ( Nueva instancia heredada ) ; Resultado := Instancia ; fin ;Para versiones anteriores, debe mover el código de clase a un módulo separado y Instancereemplazar la declaración con una declaración de una variable global en su sección (no había secciones implementationantes de Delphi 7 inclusive ). class varstrict private
Basado en el constructor de fábrica de la documentación de Dart
clase Singleton { Singleton final estático _singleton = Singleton . _interno (); fábrica Singleton () { return _singleton ; } soltero _ _interno (); }La biblioteca estándar (Ruby 1.8 y superior) incluye el módulo Singleton, que facilita aún más la creación de singletons:
requiere la clase 'singleton' Foo include Singleton end a = Foo . instancia # Foo.new no está disponible, para obtener una referencia a una (única) # instancia de la clase Foo, utilice el método Foo#instanceOpción de clase privada:
paquete { public class Singleton { private static var _instance : Singleton ; función pública Singleton ( privateClass : PrivateClass ) { } función estática pública getInstance () : Singleton { if ( ! _instance ) _instance = new Singleton ( new PrivateClass ()); volver _instancia ; } } } // Debido a que la clase se declara en el mismo archivo fuera del // paquete, solo la clase Singleton puede usarla. clase PrivateClass { función pública PrivateClass () { } }Lanzar una opción de excepción:
paquete { public class Singleton { public static const instancia : Singleton = new Singleton (); public function Singleton () { // Boolean (Singleton) es falso si la clase // se instancia antes de que se ejecute el constructor estático if ( Singleton ) arroja un nuevo error ( "La clase es singleton". ); } } }Opción con variable de acceso:
paquete { clase pública MiSingleton { privado estático var _instance : MySingleton ; // Acceder a la variable private static var _isConstructing : Boolean ; public function MySingleton () { if ( ! _isConstructing ) arroja un nuevo error ( "Singleton, use MySingleton.instance" ); } función estática pública obtener instancia () : MySingleton { if ( _instance == null ) { _isConstructing = true ; _instancia = new MiSingleton (); _esConstruyendo = falso ; } devuelve _instancia ; } } }Beneficios de la opción de clase privada:
Desventaja de la opción de clase privada:
Beneficios de la opción de excepción:
Enfoque clásico (Coffeescript ≠ 1.5)
instancia de clase Singleton = constructor indefinido : -> si instancia ? instancia de retorno otra instancia = @ # Código de constructor consola _ afirmar ( nuevo Singleton es nuevo Singleton );Enfoque basado en la capacidad de acceder a una función desde su cuerpo (Coffeescript ≠ 1.5)
class Singleton init = -> # constructor como método de clase privada # Código del constructor # ... # Reemplazar el constructor, manteniendo este (@) init = => @ return @ # Constructor real. Sirve para llamar a init # debe usarse return, de lo contrario devolverá este constructor (@) : -> return init . aplicar ( @ , argumentos ) consola _ afirmar ( nuevo Singleton es nuevo Singleton ) Nota: cambiar el constructor real de sí mismo, es decir constructor : -> Singleton = => @ No daré nada, porque en el código JavaScript resultante, el constructor apunta al constructor Singleton local, no a la clase Singleton.Sin embargo, si usa espacios de nombres, entonces esta opción es posible:
ns = {} clase ns . Constructor de singleton : -> # código de constructor ns.Singleton == > @ consola _ afirmar ( nuevo ns . Singleton es nuevo ns . Singleton )Un método basado en ocultar variables usando cierres. Como beneficio adicional, la capacidad de declarar métodos y propiedades privados que estarán disponibles tanto para el constructor como para los métodos de "clase".
const Singleton = ( función () { let instancia ; // métodos y propiedades privadas // Función constructora Singleton () { if ( instancia ) return instancia ; instancia = esto ; } // Métodos públicos Singleton . prototipo _ prueba = función () {}; volver Singleton ; })(); consola _ log ( nuevo Singleton () === nuevo Singleton ());Sin usar la ocultación de variables, hay una solución simple basada en el hecho de que la función Singleton es un objeto. La desventaja es la capacidad de cambiar la propiedad de la instancia fuera de la clase:
function Singleton () { const instancia = Singleton . instancia ; if ( instancia ) devuelve instancia ; soltero _ instancia = esto ; } soltero _ prototipo _ prueba = función () {}; consola _ log ( nuevo Singleton () === nuevo Singleton ());La opción más corta.
const Singleton = nuevo ( función () { const instancia = esto ; función de retorno () { instancia de retorno ; }; })(); consola _ log ( nuevo Singleton () === nuevo Singleton ());Usando campos privados estáticos de una clase JS:
clase Singleton { static # onlyInstance = null ; constructor (){ if ( ! Singleton . # onlyInstance ){ Singleton . # soloInstancia = esto ; } más { devuelve Singleton . # soloInstancia ; } } } consola _ log ( nuevo Singleton () === nuevo Singleton ());singleton.h
@interfaz Singleton : NSObject { } + ( Singleton * ) instancia compartida ; @finalsingleton.m
@implementaciónSingleton _ Singleton estático * _sharedInstance = nil ; + ( Singleton * ) instancia compartida { @sincronizado ( uno mismo ) { si ( ! _instancia compartida ) { _sharedInstance = [[ Singleton alloc ] init ]; } } volver _instancia compartida ; } @finalO (solo para OS X 10.6+, iOS 4.0+):
@implementaciónSingleton _ + ( Singleton * ) instancia compartida { estático dispatch_once_t pred ; Singleton estático * instancia compartida = nil ; dispatch_once ( & pred , ^ { sharedInstance = [[ self alloc ] init ]; }); volver instancia compartida ; } @finalPatrones de diseño | |
---|---|
Principal | |
Generativo | |
Estructural | |
conductual | |
Programación en paralelo |
|
arquitectónico |
|
Plantillas Java EE | |
Otras plantillas | |
Libros | |
Alusiones personales |