Hace mucho que no bloggeo, pero bueno, estoy todavía con el proyecto y con varios problemas en el backend de eso, en fin, hoy quería escribir sobre un concepto (y más que nada, patrón de diseño) que investigué y de hecho implemento en mi proyecto para realizar la conexión de mi aplicación con la BD (aun que tranquilamente puede ser aplicado a otro aspecto, pero por el momento solo lo utilicé en una parte que es la que comentaba más atrás).
El patrón "singleton" es, hasta lo que entiendo, un patrón de diseño pensado para escenarios donde se necesita que cierto elemento de nuestro código pueda ser accedido desde cualquier otra parte del proyecto y que este solo se pueda, o se deba, instanciar 1 única vez en toda la vida o tiempo de ejecución de nuestro código. El concepto en sí no es más que una clase que se instancia a sí misma una única vez (como mencioné anteriormente) y que en base a esa instanciacion podamos realizar alguna tarea sin tener que estar instanciando varias veces la misma clase. Esta clase además verífica que con anterioridad no exista una instanciación, solamente en caso de no existir una, realiza una nueva instanciacion de sí misma, de lo contrario, retorna la misma referencia hacia sí misma (xd). Respecto a esto último, realmente hay 2 formas de definir un singleton dependiendo de que y como lo queramos hacer, la primera sería que la misma instanciacion a la clase sea almacenada en un atributo estático de esta y que sea retornado en uno de sus métodos, también estático; la otra, es que el atributo que almacena la instancia, se declare nulo, y en el método que retorna la instanciacion a la misma clase, solo almacene la instanciacion (o que simplemente instancie la clase, en otras palabras) si el atributo es nulo (o sea que no tiene una instancia previa, por lo que nunca se instancio la clase), posterior a eso, que lo retorne. Normalmente la segunda opción es usada cuando necesitamos que la instanciacion de la clase se produzca solamente en un determinado momento de la ejecución del código y no necesariamente al inicio de este.
Una de las cosas importantes a tener en cuenta en este patrón es que el constructor de la clase nunca debe ser expuesto (porque nunca será, y no debe, ser usado), las instanciaciones siempre se crearan (o retornarán más bien) desde un método estático definido para usar sin instanciar a la clase. Habitualmente el constructor siempre debe tener la directiva de acceso privado, cosa de que se impida su acceso desde fuera.
Dentro de mi proyecto tengo una clase singleton definida específicamente para la conexión de mi aplicación y la BD, como estoy usando JPA, los recursos que se usan para esto es la clase "Persistence" y "EntityMangerFactory", el primero te permite crear un objeto a partir de un fichero xml que define como se debe realizar la conexión con la BD, y el segundo es básicamente el tipo de objeto que retorna la primera clase (xd). Para la agilización y optimización de este proceso (porque es un proceso pesado de hacer, ya que establece y organiza todo para realizar la conexión a BD y además es la encargada de crear otro recurso llamada "EntityManager" que como su nombre indica, administra las entidades de la BD) es altamente recomendable instanciarlo una única vez, por ende, es mejor crearle un Singleton...
Este es el singleton que cree para poder instanciar un "EntityManager" único para todo el tiempo de ejecución de mi aplicación, este singleton además puede ser accedido a todas las entidades (que lo requieran y que tengan un contexto para requerirlo) sin problema y sin necesidad de instanciarlo en cada una:
```
/*
* CLASE SINGLETON EMPLEADA PARA CONECTAR A LA BD (UNA SOLA INSTANCIACION DEL ENTITY MANAGER FACTORY)
*/
package utilidades;
import jakarta.persistence.Persistence;
import jakarta.persistence.EntityManagerFactory;
/*
*
* NOTA:
*
* SI, YA SE QUE ES RARO Y MEDIO SIN SENTIDO EL METODO INICIAR(), SI YA EL RETORNO DEL ATRIBUTO CREA LA CONEXION DEL
* EMF, PENSE QUE PARA QUE TENGA MAS CONTEXTO EL CODIGO, SERÍA BUENA IDEA EL METODO INICIAR, SI A FUTURO DA PROBLEMAS,
* LO PLANTEO DE OTRA MANERA.
*
* NO HAY PROBLEMA CON DEFINIR LA INSTANCIACION DE LA CLASE SI PREVIAMENTE NO HABÍA UNA, POR QUE EN ESTE CASO QUEREMOS
* QUE LA CLASE SE INSTANCIE APENAS SE INICIE LA APLICACION, NO NECESARIAMENTE EN ALGUN PUNTO ESPECIFICIO.
*
*/
/**
*
* @Autor: BBKMG
*/
public class EMFSingleton {
// ATRIBUTOS
private static final EMFSingleton instancia = new EMFSingleton(); // INSTANCIA DE ESTA MISMA CLASE
// private static EMFSingleton instancia = null; // NO HACE FALTA, BORRAR DESPUES
private EntityManagerFactory emf = null;
private final String UNIDADPERSISTENCIA = "persistencia";
// CONSTRUCTOR
// CONSTRUCTOR PRIVADO PARA EVITAR INSTANCIACION DESDE AFUERA
private EMFSingleton() {}
// SET
//...
// GET
public static EMFSingleton getInstancia() {
return instancia;
}
// NO HACE FALTA DEFINIR ESTO, BORRAR DESPUES
// public static EMFSingleton getInstancia() {
// if (instancia == null) {
// instancia = new EMFSingleton();
// }
//
// return instancia;
// }
// INSTANCIA EL OBJETO SOLO SI EL ATRIBUTO EMF ES NULO
public EntityManagerFactory getEMF() {
// BORRAR DESPUES
// if (this.emf == null) {
// try {
// this.emf = Persistence.createEntityManagerFactory("persistencia");
// System.out.println("[ EXITO ] > EMF iniciado correctamente!");
// } catch (Exception e) {
// System.out.println(e);
// }
// }
return this.emf;
}
// METODOS
// SOLAMENTE INSTANCIA 1 SOLA VEZ EL EMF (O DIGAMOS QUE ESTABLECE LA CONEXION A BD 1 SOLA VEZ)
public void iniciarEMF() {
if (this.emf != null) {
System.out.println("[ EXITO ] > El EMF ya fué iniciado!");
return;
}
try {
this.emf = Persistence.createEntityManagerFactory(UNIDADPERSISTENCIA);
System.out.println("[ EXITO ] > EMF iniciado correctamente!");
} catch (Exception e) {
System.out.println(e);
}
}
// OBVIAMENTE ESTO MATA LA CONEXION A BD
public void cerrarEMF() {
if (this.emf != null && this.emf.isOpen()) {
this.emf.close();
System.out.println("[ EXITO ] > EMF finalizado correctamente!");
}
}
}
```
(Es parte del código de mi aplicación, y si, no me lo deja poner como código, pero bueno)
Y hasta el momento esto funciona de forma correcta, leí que el patrón singleton es medio propenso a joderse si se utilizan hilos múltiples (ya que por A o por B si ambos hilos instancian a la clase al mismo tiempo pueden pasar 2 cosas, romperse el patrón por haber más de una instanciacion, o que todo falle al carajo), yo hasta el momento no hago uso de hilos, así que no me preocupo por eso.