Solitario (patrón de diseño)

La versión actual de la página aún no ha sido revisada por colaboradores experimentados y puede diferir significativamente de la versión revisada el 15 de noviembre de 2020; la verificación requiere 101 ediciones .
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

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.

Propósito

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:

Ventajas

Contras

Aplicación

Ejemplos de uso

Ejemplos de implementación

Java 1.6

Ejemplo de Java 1.6: sin clases internas (implementación perezosa no sincronizada) Singleton de clase pública { instancia de Singleton estática privada ; Singleton privado () {}; Singleton estático público getInstance () { if ( instancia == nulo ) { instancia = new Singleton (); } instancia de retorno ; } }

Java

Ejemplo de Java: Accesor sincronizado

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 ; } }

Java

Ejemplo de Java: sin inicialización perezosa, usando un inicializador estático Singleton de clase pública { instancia de Singleton estática privada ; estático { instancia = nuevo Singleton (); // El manejo de excepciones es posible en este bloque } Singleton privado () {} getInstance de Singleton estático público () { instancia de retorno ; } }

Java 1.5

Ejemplo de Java 1.5: Titular de inicialización bajo demanda Singleton de clase pública { Singleton privado () {} clase estática privada SingletonHolder { instancia de Singleton final estática pública = new Singleton (); } getInstance Singleton público estático () { return SingletonHolder . instancia ; } }

Java 1.5

Ejemplo de Java 1.5: Enum singleton public enum SingletonEnum { INSTANCIA ; public void algunMetodo () { *** } public void otro método () { *** } }

Pitón

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 : ...

Pitón

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 ): ...

C++

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 ;

C#

Ejemplo en C#

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 () { } } }

PHP 4

Ejemplo en PHP4 <?php clase Singleton { function Singleton ( $directCall = true ) { if ( $directCall ) { trigger_error ( "No se puede usar el constructor para crear la clase Singleton. Use el método estático getInstance()" , E_USER_ERROR ); } //TODO: Agregue el código del constructor principal aquí } function & getInstance () { static $instancia ; if ( ! es_objeto ( $instancia ) ) { $clase = __CLASE__ ; $instancia = nueva $clase ( false ); } devuelve $instancia ; } } //uso $prueba = & Singleton :: getInstance (); ?>

PHP5

Ejemplo en PHP5 <?php class Singleton { private static $instancia ; // función privada de instancia de objeto __construct (){ /* ... @return Singleton */ } // Proteger de la creación a través de la nueva función privada Singleton __clone () { /* ... @return Singleton */ } // Proteger de creación a través de la clonación función privada __wakeup () { /* ... @return Singleton */ } // Proteger de la creación a través de la función estática pública no serializada getInstance () { // Devuelve una sola instancia de la clase. @return Singleton if ( vacío ( self :: $instancia ) ) { self :: $instancia = new self (); } return self :: $instancia ; } función pública hacerAcción () { } } /* Aplicación */ Singleton :: getInstance () -> doAction (); // ?>

PHP 5.4

Ejemplo en PHP5.4 <?php trait Singleton { private static $instancia = null ; función privada __construct () { /* ... @return Singleton */ } // Proteger de la creación a través de la nueva función privada de Singleton __clone () { /* ... @return Singleton */ } // Proteger de la creación a través de la clonación privada function __wakeup () { /* ... @return Singleton */ } // Proteger de la creación a través de la deserialización función estática pública getInstance () { return self :: $instancia === nulo ? self :: $instancia = new static () // Si $instancia es 'nulo', cree un objeto nuevo self() : self :: $instancia ; // De lo contrario, devuelve un objeto existente } } /** * Class Foo * @method static Foo getInstance() */ class Foo { use Singleton ; privada $barra = 0 ; public function incBar () { $this -> bar ++ ; } public function getBar () { return $this -> bar ; } } /* Solicitud */ $foo = foo :: getInstance (); $foo -> incBar (); var_dump ( $foo -> getBar ()); $foo = foo :: getInstance (); $foo -> incBar (); var_dump ( $foo -> getBar ()); ?>

Delfos

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

dardo

Ejemplo de dardo

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 (); }

Yo

yo ejemplo Singleton := Objeto clonar Singleton clonar := Singleton

Rubí

Ejemplo en rubí clase Singleton def auto . nueva @instancia ||= super final final

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#instance

Ceceo común

Ejemplo en Common Lisp ( defclass singleton-class () ;; metaclase que implementa el mecanismo singleton (( instancia :initform nil ))) ( defmethod validar-superclase (( class singleton-class ) ( superclass standard-class )) t ) ;;Permitir que las clases singleton hereden de las clases normales ( defmethod validar-superclase (( class singleton-class ) ( superclass singleton-class )) t ) ;;Permitir que las clases singleton hereden de otras clases singleton ( defmethod validate-superclass (( class standard-class ) ( superclass singleton-class )) nil ) ;;Prohibir que las clases ordinarias hereden de singletons ( defmethod make-instance (( clase singleton-class ) &key ) ( with-slots ( instancia ) clase ( o instancia ( setf instancia ( call-next-method ))))) ( defclass mi-clase-singleton () () ( :metaclass clase-singleton ))

VB.NET

Ejemplo en VB.NET Programa del módulo Sub Main () Dim T1 As Singleton = Singleton . obtenerInstancia T1 . valor = 1000 Dim T2 como Singleton = Singleton . consola getInstance . WriteLine ( T2 . Valor ) consola _ Leer () Fin sub Módulo final Singleton de clase pública Valor público como entero 'No permitir el constructor Sub protegido Nuevo () End Sub Private NotInheritable Class SingletonCreator Private Shared Solo lectura m_instance As New Singleton ( ) Instancia de propiedad pública compartida de solo lectura () As Singleton Obtener Retorno m_instance End Obtener End Property End Class Propiedad pública compartida de solo lectura getInstance () como Singleton Get Return SingletonCreator . Fin de instancia Obtener propiedad final clase final

perl

Ejemplo de Perl usar v5.10 ; _ uso estricto ; paquete Singleton ; sub new { # Declarar una variable estática $instancia # y devolverla como resultado de ejecutar el método new state $instancia = bendecir {}; } paquete principal ; mi $a = Singleton -> nuevo ; mi $b = Singleton -> nuevo ; decir "$a $b" ; # Las referencias $a y $b apuntan al mismo objeto

perl

Ejemplo de Perl con objeto inmutable #!/usr/bin/perl-w usar la función "decir" ; uso estricto ; advertencias de uso ; paquete Singleton { mi $instancia ; # instancia de clase (campo estático) # -- ** constructor ** -- sub new { mi $clase = shift ; a menos que ( $instancia ) { # verifique si ya existe una instancia de la clase $instancia = { # si no, cree una nueva y escriba el nombre de la persona para saludarla name => shift , }; bless $instancia , $clase ; } devuelve $instancia ; # devolver la única instancia de nuestra clase } # -- ** hola ** -- sub hola { my ( $self ) = ( shift ); say "Hola, $self->{name}" ; # saludemos al propietario de este objeto } } mi $a = Singleton -> nuevo ( 'Alex' ); # crear una instancia de una clase llamada Alex my $b = Singleton -> new ( 'Barney' ); # ... ahora tratando de crear otra instancia para Barney $a -> hola (); # Hola, Alex # sí, hola Alex $b -> hola (); # Hola, Alex # Vaya, Barney, lo siento, qué malentendido...

ActionScript 3

Ejemplo de ActionScript

Opció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:

  • Si intenta usar el constructor directamente, el compilador detectará el error de inmediato. // No es el único beneficio de este método
  • El objeto se crea a petición.

Desventaja de la opción de clase privada:

  • Puede reemplazar la clase privada con la suya propia con el mismo nombre.

Beneficios de la opción de excepción:

  • Menos código.

CoffeeScript

Ejemplo en CoffeeScript

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 )

JavaScript

Ejemplo de JavaScript con encapsulación

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 ());

Objetivo-C

Ejemplo en Objective-C

singleton.h

@interfaz Singleton  : NSObject { } + ( Singleton * ) instancia compartida ; @final

singleton.m

@implementaciónSingleton _ Singleton estático * _sharedInstance = nil ; + ( Singleton * ) instancia compartida { @sincronizado ( uno mismo ) { si ( ! _instancia compartida ) { _sharedInstance = [[ Singleton alloc ] init ]; } } volver _instancia compartida ; } @final

O (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 ; } @final

Rápido

Ejemplo rápido class Singleton { static let shared = Singleton () private init () { } }

Scala, Kotlin

Ejemplo en Scala y Kotlin object Singleton {} // palabra clave "objeto" crea una clase que implementa el patrón "singleton" por defecto

Véase también

Literatura

  • Alan Shalloway, James R. Trott Patrones de diseño. Un nuevo enfoque del diseño orientado a objetos = explicación de los patrones de diseño: una nueva perspectiva del diseño orientado a objetos. - M.: "Williams", 2002. - S. 288. - ISBN 0-201-71594-5 .
  • Eric Freeman, Elizabeth Freeman. Patrones de diseño = Patrones de diseño Head First. - San Petersburgo. : Pedro, 2011. - 656 p. - ISBN 978-5-459-00435-9 .

Enlaces

Notas