Tema 13 · Patrón Singleton

Patrón Singleton y Module Pattern en JavaScript

Aprende a implementar el patrón creacional Singleton en JavaScript ES6 para garantizar una única instancia global y conoce el clásico Module Pattern.

¿Qué es el Patrón Singleton?

El Singleton es uno de los patrones de diseño creacionales más conocidos. Su objetivo es garantizar que una clase tenga una única instancia en toda la vida de la aplicación y proporcionar un punto de acceso global a ella.

Es indispensable para recursos que deben ser compartidos y coherentes:

  • Almacén de Estado Global: Un único carrito de compras o store de usuario.
  • Pool de Conexiones a Base de Datos: No tiene sentido abrir 500 conexiones simultáneas si se puede reutilizar un único pool central.
  • Gestor de Configuración: Lectura de variables de entorno de la aplicación.

Implementación Moderna de Singleton en ES6

En JavaScript, podemos aprovechar que el constructor puede retornar un objeto explícito para devolver la instancia existente si ya fue creada:

class Configuracion {
    static #instancia = null;

    constructor() {
        if (Configuracion.#instancia) {
            return Configuracion.#instancia; // Retorna la instancia previa
        }
        this.tema = "oscuro";
        Configuracion.#instancia = this;
    }
}

Si alguien hace new Configuracion() 100 veces, siempre obtendrá exactamente el mismo objeto en memoria RAM.

Inmutabilidad con `Object.freeze()`

Para evitar que otras partes del código alteren o borren propiedades del Singleton, sellamos la instancia utilizando Object.freeze(this).

⚡ Gestor de Estado y Configuración Global con Patrón Singleton

Ejecuta el código en el Sandbox y comprueba que ambas variables apuntan a la misma instancia en memoria:

SingletonDemo.js
Solo lectura
// Implementación de Singleton en ES6
class GestorEstadoGlobal {
    static #instanciaUnica = null;

    constructor() {
        // Si ya fue instanciada, retornamos la misma referencia de memoria
        if (GestorEstadoGlobal.#instanciaUnica) {
            return GestorEstadoGlobal.#instanciaUnica;
        }

        // Estado inicial de la aplicación
        this.sesionIniciada = false;
        this.usuarioActivo = null;
        this.idioma = "es";
        this.idInstancia = Math.random().toString(36).substring(2, 9);

        // Guardamos la referencia única
        GestorEstadoGlobal.#instanciaUnica = this;
    }

    iniciarSesion(usuario) {
        this.sesionIniciada = true;
        this.usuarioActivo = usuario;
        console.log(` Sesión iniciada globalmente para: ${usuario.nombre}`);
    }

    cerrarSesion() {
        this.sesionIniciada = false;
        this.usuarioActivo = null;
        console.log(" Sesión cerrada globalmente.");
    }

    obtenerEstado() {
        return {
            idInstancia: this.idInstancia,
            autenticado: this.sesionIniciada,
            usuario: this.usuarioActivo ? this.usuarioActivo.nombre : "Anónimo",
            idioma: this.idioma
        };
    }
}

// ==========================================
// PRUEBA EN EL SANDBOX
// ==========================================
console.log("=== CREANDO INSTANCIA 1 EN MÓDULO A ===");
const estadoEnModuloA = new GestorEstadoGlobal();
console.log("Estado inicial:", estadoEnModuloA.obtenerEstado());

// Iniciamos sesión en el Módulo A
estadoEnModuloA.iniciarSesion({ nombre: "Carlos Mendoza", rol: "Admin" });

console.log("\n=== CREANDO INSTANCIA 2 EN MÓDULO B ===");
// En otro archivo completamente distinto, alguien hace "new GestorEstadoGlobal()"
const estadoEnModuloB = new GestorEstadoGlobal();

console.log("Estado leído desde Módulo B:", estadoEnModuloB.obtenerEstado());

console.log("\n=== COMPROBACIÓN DE IDENTIDAD EN MEMORIA RAM ===");
const sonIdenticos = (estadoEnModuloA === estadoEnModuloB);
console.log("¿estadoEnModuloA === estadoEnModuloB?:", sonIdenticos); // true!
console.log(`ID Instancia A: ${estadoEnModuloA.idInstancia}`);
console.log(`ID Instancia B: ${estadoEnModuloB.idInstancia}`);
Pruébalo tú mismo » Se abre en una nueva pestaña con ejecución en vivo
🧠
Mini-Quiz de Retención
Comprueba tu comprensión antes de pasar a la siguiente lección
1 Pregunta
Pregunta 1
¿Cuál es el objetivo principal del patrón de diseño Singleton?
🦉
¿Tienes dudas con este tema?
Sócrates AI puede darte analogías y explicarte este código paso a paso.

🚀 ¿Quieres dominar Manual de Programación Orientada a Objetos en JavaScript (POO) y crear proyectos reales?

Aprende arquitectura limpia, desarrollo web moderno, buenas prácticas y despliegue en producción con nuestro Bootcamp Fullstack Developer con mentorías en vivo.

🏛️ Autoría y Propiedad Intelectual: Obra educativa original de David Amador para Kilopolis Academia (Solucionáticos), estructurada sobre las especificaciones y estándares abiertos del W3C, el estándar vivo de WHATWG y la documentación oficial de código abierto. © Todos los derechos reservados.