Design patterns
Semifallo
Buscar..
Observaciones
El patrón de diseño de Singleton a veces se considera como " patrón Anti ". Esto se debe al hecho de que tiene algunos problemas. Tienes que decidir por ti mismo si crees que es apropiado usarlo. Este tema ha sido discutido varias veces en StackOverflow.
Consulte: http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons
Singleton (C #)
Los Singletons se utilizan para garantizar que solo se está creando una instancia de un objeto. El singleton permite que solo se cree una instancia de sí mismo, lo que significa que controla su creación. El singleton es uno de los patrones de diseño de Gang of Four y es un patrón de creación .
Patrón Singleton seguro para hilos
public sealed class Singleton
{
private static Singleton _instance;
private static object _lock = new object();
private Singleton()
{
}
public static Singleton GetSingleton()
{
if (_instance == null)
{
CreateSingleton();
}
return _instance;
}
private static void CreateSingleton()
{
lock (_lock )
{
if (_instance == null)
{
_instance = new Singleton();
}
}
}
}
Jon Skeet proporciona la siguiente implementación para un singleton perezoso y seguro para subprocesos:
public sealed class Singleton
{
private static readonly Lazy<Singleton> lazy =
new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance { get { return lazy.Value; } }
private Singleton()
{
}
}
Singleton (Java)
Los Singletons en Java son muy similares a C #, ya que ambos lenguajes están orientados a objetos. A continuación se muestra un ejemplo de una clase singleton, donde solo una versión del objeto puede estar activa durante la vida útil del programa (Suponiendo que el programa funcione en un solo hilo)
public class SingletonExample {
private SingletonExample() { }
private static SingletonExample _instance;
public static SingletonExample getInstance() {
if (_instance == null) {
_instance = new SingletonExample();
}
return _instance;
}
}
Aquí está la versión segura de hilo de ese programa:
public class SingletonThreadSafeExample {
private SingletonThreadSafeExample () { }
private static volatile SingletonThreadSafeExample _instance;
public static SingletonThreadSafeExample getInstance() {
if (_instance == null) {
createInstance();
}
return _instance;
}
private static void createInstance() {
synchronized(SingletonThreadSafeExample.class) {
if (_instance == null) {
_instance = new SingletonThreadSafeExample();
}
}
}
}
Java también tiene un objeto llamado ThreadLocal
, que crea una única instancia de un objeto en una base hilo por hilo. Esto podría ser útil en aplicaciones donde cada hilo necesita su propia versión del objeto.
public class SingletonThreadLocalExample {
private SingletonThreadLocalExample () { }
private static ThreadLocal<SingletonThreadLocalExample> _instance = new ThreadLocal<SingletonThreadLocalExample>();
public static SingletonThreadLocalExample getInstance() {
if (_instance.get() == null) {
_instance.set(new SingletonThreadLocalExample());
}
return _instance.get();
}
}
Aquí también hay una implementación de Singleton con enum
(que contiene solo un elemento):
public enum SingletonEnum {
INSTANCE;
// fields, methods
}
Cualquier implementación de clase Enum asegura que solo existirá una instancia de cada elemento.
Bill Pugh Singleton patrón
Bill Pugh Singleton Pattern es el enfoque más utilizado para la clase Singleton, ya que no requiere sincronización
public class SingletonExample {
private SingletonExample(){}
private static class SingletonHolder{
private static final SingletonExample INSTANCE = new SingletonExample();
}
public static SingletonExample getInstance(){
return SingletonHolder.INSTANCE;
}
}
con el uso de una clase estática interna privada, el titular no se carga en la memoria hasta que alguien llame al método getInstance. La solución de Bill Pugh es segura para subprocesos y no requiere sincronización.
Hay más ejemplos de Java singleton en el tema Singletons bajo la etiqueta de documentación de Java.
Singleton (C ++)
Según Wiki : en ingeniería de software, el patrón de singleton es un patrón de diseño que restringe la creación de instancias de una clase a un objeto.
Esto es necesario para crear exactamente un objeto para coordinar acciones en todo el sistema.
class Singleton
{
// Private constructor so it can not be arbitrarily created.
Singleton()
{}
// Disable the copy and move
Singleton(Singleton const&) = delete;
Singleton& operator=(Singleton const&) = delete;
public:
// Get the only instance
static Singleton& instance()
{
// Use static member.
// Lazily created on first call to instance in thread safe way (after C++ 11)
// Guaranteed to be correctly destroyed on normal application exit.
static Singleton _instance;
// Return a reference to the static member.
return _instance;
}
};
Lazy Singleton ejemplo práctico en java.
Casos de uso de la vida real para el patrón Singleton;
Si está desarrollando una aplicación cliente-servidor, necesita una única entrada de ConnectionManager
, que administra el ciclo de vida de las conexiones de clientes.
Las APIs básicas en ConnectionManager:
registerConnection
: Agregar nueva conexión a la lista de conexiones existente
closeConnection
: closeConnection
la conexión ya sea del evento desencadenado por el Cliente o el Servidor
broadcastMessage
: algunas veces, debe enviar un mensaje a todas las conexiones de clientes suscritas.
No estoy proporcionando una implementación completa del código fuente ya que el ejemplo será muy largo. A alto nivel, el código será así.
import java.util.*;
import java.net.*;
/* Lazy Singleton - Thread Safe Singleton without synchronization and volatile constructs */
final class LazyConnectionManager {
private Map<String,Connection> connections = new HashMap<String,Connection>();
private LazyConnectionManager() {}
public static LazyConnectionManager getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final LazyConnectionManager INSTANCE = new LazyConnectionManager();
}
/* Make sure that De-Serailzation does not create a new instance */
private Object readResolve() {
return LazyHolder.INSTANCE;
}
public void registerConnection(Connection connection){
/* Add new connection to list of existing connection */
connections.put(connection.getConnectionId(),connection);
}
public void closeConnection(String connectionId){
/* Close connection and remove from map */
Connection connection = connections.get(connectionId);
if ( connection != null) {
connection.close();
connections.remove(connectionId);
}
}
public void broadcastMessage(String message){
for (Map.Entry<String, Connection> entry : connections.entrySet()){
entry.getValue().sendMessage(message);
}
}
}
Clase de servidor de muestra:
class Server implements Runnable{
ServerSocket socket;
int id;
public Server(){
new Thread(this).start();
}
public void run(){
try{
ServerSocket socket = new ServerSocket(4567);
while(true){
Socket clientSocket = socket.accept();
++id;
Connection connection = new Connection(""+ id,clientSocket);
LazyConnectionManager.getInstance().registerConnection(connection);
LazyConnectionManager.getInstance().broadcastMessage("Message pushed by server:");
}
}catch(Exception err){
err.printStackTrace();
}
}
}
Otros casos de uso práctico para Singletons:
- Administración de recursos globales como
ThreadPool, ObjectPool, DatabaseConnectionPool
etc. - Servicios centralizados como el
Logging
datos de aplicaciones con diferentes niveles de registro comoDEBUG,INFO,WARN,ERROR
etc. - Global
RegistryService
donde se registran diferentes servicios con un componente central en el inicio. Ese servicio global puede actuar como unaFacade
para la aplicación
Ejemplo de C #: Singleton multiproceso
La inicialización estática es adecuada para la mayoría de las situaciones. Cuando su aplicación debe retrasar la creación de instancias, use un constructor no predeterminado o realice otras tareas antes de la creación de instancias, y trabaje en un entorno de multiproceso, necesita una solución diferente. Sin embargo, existen casos en los que no puede confiar en el tiempo de ejecución del lenguaje común para garantizar la seguridad de los subprocesos, como en el ejemplo de Inicialización Estática. En tales casos, debe usar capacidades de lenguaje específicas para garantizar que solo se cree una instancia del objeto en presencia de varios subprocesos. Una de las soluciones más comunes es utilizar el modismo Double-Check Locking [Lea99] para evitar que los hilos separados creen nuevas instancias del singleton al mismo tiempo.
La siguiente implementación permite que solo un subproceso ingrese al área crítica, que el bloque de bloqueo identifica, cuando aún no se ha creado una instancia de Singleton:
using System;
public sealed class Singleton {
private static volatile Singleton instance;
private static object syncRoot = new Object();
private Singleton() {}
public static Singleton Instance {
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}
Este enfoque garantiza que solo se crea una instancia y solo cuando la instancia es necesaria. Además, la variable se declara volátil para garantizar que la asignación a la variable de instancia se complete antes de poder acceder a la variable de instancia. Por último, este enfoque utiliza una instancia de syncRoot para bloquear, en lugar de bloquear el propio tipo, para evitar puntos muertos.
Este enfoque de bloqueo de doble comprobación resuelve los problemas de concurrencia de hilos al tiempo que evita un bloqueo exclusivo en cada llamada al método de propiedad de instancia. También le permite retrasar la creación de instancias hasta que se acceda por primera vez al objeto. En la práctica, una aplicación rara vez requiere este tipo de implementación. En la mayoría de los casos, el enfoque de inicialización estática es suficiente.
Referencia: MSDN
Expresiones de gratitud
[Gamma95] Gamma, Helm, Johnson y Vlissides. Patrones de diseño: elementos de software orientado a objetos reutilizables. Addison-Wesley, 1995.
[Lea99] Lea, Doug. Programación concurrente en Java, Segunda Edición. Addison-Wesley, 1999.
[Vende03] Vende, Chris. "Sellado chupa". sellsbrothers.com Noticias. Disponible en: http://www.sellsbrothers.com/news/showTopic.aspx?ixTopic=411 .
Singleton (PHP)
Ejemplo de phptherightway.com
<?php class Singleton { /** * @var Singleton The reference to *Singleton* instance of this class */ private static $instance; /** * Returns the *Singleton* instance of this class. * * @return Singleton The *Singleton* instance. */ public static function getInstance() { if (null === static::$instance) { static::$instance = new static(); } return static::$instance; } /** * Protected constructor to prevent creating a new instance of the * *Singleton* via the `new` operator from outside of this class. */ protected function __construct() { } /** * Private clone method to prevent cloning of the instance of the * *Singleton* instance. * * @return void */ private function __clone() { } /** * Private unserialize method to prevent unserializing of the *Singleton* * instance. * * @return void */ private function __wakeup() { } } class SingletonChild extends Singleton { } $obj = Singleton::getInstance(); var_dump($obj === Singleton::getInstance()); // bool(true) $anotherObj = SingletonChild::getInstance(); var_dump($anotherObj === Singleton::getInstance()); // bool(false) var_dump($anotherObj === SingletonChild::getInstance()); // bool(true)
Patrón Singleton Design (en general)
Nota: El singleton es un patrón de diseño.
Pero también se considera un anti-patrón.
El uso de un singleton debe considerarse cuidadosamente antes de su uso. Usualmente hay mejores alternativas.
El problema principal con un singleton es el mismo que el problema con las variables globales. Introducen el estado mutable global externo. Esto significa que las funciones que usan un singleton no dependen únicamente de los parámetros de entrada, sino también del estado del singleton. Esto significa que las pruebas pueden verse gravemente comprometidas (difíciles).
Los problemas con singletons pueden mitigarse usándolos junto con los patrones de creación; para que la creación inicial del singleton pueda ser controlada.