Prácticas de patrones de diseño Java Singleton con ejemplos

En artículos anteriores , discutimos en detalle  sobre el patrón de diseño singleton y la implementación de la clase singleton.
En este artículo, veremos cómo podemos crear clases singleton. Después de leer este artículo, podrá crear su clase singleton de acuerdo con sus requisitos, que es simple y sin cuellos de botella. 
Hay muchas maneras de hacer esto en Java. Todas estas formas difieren en la implementación del patrón, pero al final, todas logran el mismo resultado final de una sola instancia. 
 

  1. Inicialización ansiosa: este es el método más simple para crear una clase singleton. En esto, el objeto de clase se crea cuando JVM lo carga en la memoria. Se realiza asignando la referencia de una instancia directamente. 
    Se puede usar cuando el programa siempre usará una instancia de esta clase, o el costo de crear la instancia no es demasiado alto en términos de recursos y tiempo.
     

JAVA

// Java code to create singleton class by
// Eager Initialization
public class GFG
{
  // public instance initialized when loading the class
  private static final GFG instance = new GFG();
 
  private GFG()
  {
    // private constructor
  }
  public static GFG getInstance(){
        return instance;
    }
}
  1. Ventajas:
    1. Muy simple de implementar.
    2. Puede conducir al desperdicio de recursos. Porque la instancia de clase se crea siempre, ya sea que se requiera o no.
    3. El tiempo de CPU también se desperdicia en la creación de instancias si no es necesario.
    4. El manejo de excepciones no es posible.
  2. Uso de bloque estático: esta también es una parte secundaria de la inicialización de Eager. La única diferencia es que el objeto se crea en un bloque estático para que podamos tener acceso a su creación, como el manejo de excepciones. De esta manera también, el objeto se crea en el momento de la carga de la clase. 
    Se puede usar cuando existe la posibilidad de excepciones en la creación de objetos con una inicialización ansiosa. 
     

JAVA

// Java code to create singleton class
// Using Static block
public class GFG
{
  // public instance
  public static GFG instance;
 
  private GFG()
  {
    // private constructor
  }
static
  {
    // static block to initialize instance
    instance = new GFG();
  }
}
  1. Ventajas:
    1. Muy simple de implementar.
    2. No es necesario implementar el método getInstance(). Se puede acceder a la instancia directamente.
    3. Las excepciones se pueden manejar en bloque estático.
    4. Puede conducir al desperdicio de recursos. Porque la instancia de clase se crea siempre, ya sea que se requiera o no.
    5. El tiempo de CPU también se desperdicia en la creación de instancias si no es necesario.
  2. Inicialización diferida: en este método, el objeto se crea solo si es necesario. Esto puede evitar el desperdicio de recursos. Se requiere una implementación del método getInstance() que devuelva la instancia. Hay una verificación nula de que si el objeto no se crea, cree, de lo contrario, devuelva el creado previamente. Para asegurarse de que la clase no se pueda instanciar de ninguna otra manera, el constructor se hace final. Como el objeto se crea con un método, garantiza que el objeto no se creará hasta que sea necesario. La instancia se mantiene privada para que nadie pueda acceder a ella directamente. 
    Se puede usar en un entorno de un solo subproceso porque varios subprocesos pueden romper la propiedad singleton, ya que pueden acceder al método de instancia de obtención simultáneamente y crear varios objetos. 
     

JAVA

//Java Code to create singleton class
// With Lazy initialization
public class GFG
{
  // private instance, so that it can be
  // accessed by only by getInstance() method
  private static GFG instance;
 
  private GFG()
  {
    // private constructor
  }
 
  //method to return instance of class
  public static GFG getInstance()
  {
    if (instance == null)
    {
      // if instance is null, initialize
      instance = new GFG();
    }
    return instance;
  }
}
  1. Ventajas:
    1. El objeto se crea solo si es necesario. Puede superar el desperdicio de recursos y tiempo de CPU.
    2. El manejo de excepciones también es posible en el método.
    3. Cada vez que se debe verificar una condición de nulo.
    4. No se puede acceder a la instancia directamente.
    5. En un entorno de subprocesos múltiples, puede romper la propiedad singleton.
  2. Singleton seguro para subprocesos: se crea un singleton seguro para subprocesos para que la propiedad singleton se mantenga incluso en un entorno de subprocesos múltiples. Para hacer que un subproceso de clase singleton sea seguro, el método getInstance() se sincroniza para que varios subprocesos no puedan acceder a él simultáneamente.
     

JAVA

// Java program to create Thread Safe
// Singleton class
public class GFG
{
  // private instance, so that it can be
  // accessed by only by getInstance() method
  private static GFG instance;
 
  private GFG()
  {
    // private constructor
  }
 
 //synchronized method to control simultaneous access
  synchronized public static GFG getInstance()
  {
    if (instance == null)
    {
      // if instance is null, initialize
      instance = new GFG();
    }
    return instance;
  }
}
  1. Ventajas:
    1. La inicialización diferida es posible.
    2. También es seguro para subprocesos.
    3. El método getInstance() está sincronizado, por lo que provoca un rendimiento lento ya que varios subprocesos no pueden acceder a él simultáneamente.
  2. Inicialización diferida con bloqueo de doble verificación: en este mecanismo, superamos el problema general del código sincronizado. En este método, getInstance no está sincronizado, pero el bloque que crea la instancia está sincronizado, de modo que la cantidad mínima de subprocesos tiene que esperar y eso es solo por primera vez.
     

JAVA

// Java code to explain double check locking
public class GFG
{
  // private instance, so that it can be
  // accessed by only by getInstance() method
  private static GFG instance;
 
  private GFG()
  {
    // private constructor
  }
 
  public static GFG getInstance()
  {
    if (instance == null)
    {
      //synchronized block to remove overhead
      synchronized (GFG.class)
      {
        if(instance==null)
        {
          // if instance is null, initialize
          instance = new GFG();
        }
       
      }
    }
    return instance;
  }
}
  1. Ventajas:
    1. La inicialización diferida es posible.
    2. También es seguro para subprocesos.
    3. La sobrecarga de rendimiento se reduce debido a la palabra clave sincronizada.
    4. La primera vez, puede afectar el rendimiento.
  2. Implementación de Bill Pugh Singleton: antes de Java5, el modelo de memoria tenía muchos problemas y los métodos anteriores causaban fallas en ciertos escenarios en entornos de subprocesos múltiples. Entonces, Bill Pugh sugirió un concepto de clases estáticas internas para usar en singleton.
     

JAVA

// Java code for Bill Pugh Singleton Implementation
public class GFG
{
 
  private GFG()
  {
    // private constructor
  }
 
  // Inner class to provide instance of class
  private static class BillPughSingleton
  {
    private static final GFG INSTANCE = new GFG();
  }
 
  public static GFG getInstance()
  {
    return BillPughSingleton.INSTANCE;
  }
}
  1. Cuando se carga la clase singleton, la clase interna no se carga y, por lo tanto, no crea un objeto al cargar la clase. La clase interna se crea solo cuando se llama al método getInstance(). Por lo tanto, puede parecer una inicialización ansiosa, pero es una inicialización perezosa. 
    Este es el enfoque más utilizado, ya que no utiliza la sincronización.

Cuándo usar Qué

  1. La inicialización ansiosa es fácil de implementar, pero puede causar un desperdicio de recursos y tiempo de CPU. Úselo solo si el costo de inicializar una clase es menor en términos de recursos o si su programa siempre necesitará la instancia de la clase.
  2. Al usar el bloque estático en la inicialización de Eager, podemos proporcionar el manejo de excepciones y también podemos controlar la instancia.
  3. Al usar sincronizado, también podemos crear una clase singleton en un entorno de subprocesos múltiples, pero puede causar un rendimiento lento, por lo que podemos usar el mecanismo de bloqueo de verificación doble. 
     
  4. La implementación de Bill Pugh es el enfoque más utilizado para las clases singleton. La mayoría de los desarrolladores lo prefieren por su simplicidad y ventajas.

Este artículo es una contribución de Vishal Garg . Si te gusta GeeksforGeeks y te gustaría contribuir, también puedes escribir un artículo usando write.geeksforgeeks.org o enviar tu artículo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.
Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.
 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *