En un articulo anterior habíamos resaltado la importancia de los patrones de diseño en la programación y el porque deberíamos utilizarlos en nuestros proyectos, en este articulo vamos a realizar dos formas de implementar el famoso patrón de diseño Singleton en Java.
Singleton basado en clases
El enfoque más popular en la utilización de los patrones de diseño es implementar un Singleton creando una clase regular y asegurándose de que tenga:
- Un constructor privado
- Un campo estático que contiene su única instancia
- Un método de fábrica estático para obtener la instancia
También agregaremos una propiedad de información, esto con el fin de usarlo posteriormente. Por lo tanto, nuestra implementación se verá así:
public final class ClassSingleton { private static ClassSingleton INSTANCE; private String info = "Initial info class"; private ClassSingleton() { } // Forma de instanciación public static ClassSingleton getInstance() { if(INSTANCE == null) { INSTANCE = new ClassSingleton(); } return INSTANCE; } // getters y setters de la clase }
Si bien este es un enfoque común, es importante tener en cuenta que puede ser problemático en escenarios de subprocesamiento múltiple, que es la razón principal para usar Singletons.
En pocas palabras, puede dar como resultado más de una instancia, rompiendo el principio básico del patrón. Aunque definitivamente existen soluciones de bloqueo para este problema, nuestro próximo enfoque resuelve estos problemas a nivel de raíz.
Enum Singleton
Otro enfoque muy interesante es usar enumeraciones en las que también podemos aplicar patrones de diseño, de tal forma que nuestra implementación quede de la siguiente manera:
public enum EnumSingleton { INSTANCE("Información Inicial de la clase"); private String info; private EnumSingleton(String info) { this.info = info; } // Metodo de instanciación del Enum public EnumSingleton getInstance() { return INSTANCE; } // getters y setters de la clase }
Este enfoque tiene la serialización y la seguridad de subprocesos garantizados por la implementación de enum, que asegura internamente que solo está disponible la instancia única, corrigiendo los problemas señalados en la implementación basada en clases.
Forma de uso
Para usar nuestro ClassSingleton, simplemente necesitamos obtener la instancia estáticamente:
ClassSingleton classSingleton1 = ClassSingleton.getInstance(); System.out.println(classSingleton1.getInfo()); //Información inicial de la clase ClassSingleton classSingleton2 = ClassSingleton.getInstance(); classSingleton2.setInfo("Información de la nueva Clase"); System.out.println(classSingleton1.getInfo()); //Información de la nueva Clase1 System.out.println(classSingleton2.getInfo()); //Información de la nueva Clase2
En cuanto a EnumSingleton, podemos usarlo como cualquier otro Java Enum:
EnumSingleton enumSingleton1 = EnumSingleton.INSTANCE.getInstance(); System.out.println(enumSingleton1.getInfo()); ////Información inicial de la clase EnumSingleton enumSingleton2 = EnumSingleton.INSTANCE.getInstance(); enumSingleton2.setInfo("Nueva información de enum"); System.out.println(enumSingleton1.getInfo()); // Nueva información de enum1 System.out.println(enumSingleton2.getInfo()); // Nueva información de enum2
Conclusión
En este articulo nos enfocamos en cómo implementar el patrón de Singleton utilizando solo Java, y cómo asegurarnos de que sea consistente y cómo hacer uso de estas implementaciones en nuestros proyectos.