Patrón Singleton

Patrón Singleton

🧠 ¿Qué es el patrón Singleton?
El patrón Singleton es un patrón de diseño creacional que garantiza que una clase tenga una única instancia y proporciona un punto de acceso global a ella. Es útil cuando necesitas exactamente un objeto para coordinar acciones en todo el sistema (por ejemplo, una conexión a base de datos, un logger, una configuración global, etc.).

🧙‍♂️ Ejemplo: El Anillo Único (Singleton)

<?php

class AnilloUnico {
    // Propiedad estática para almacenar la instancia única
    private static $instancia = null;
    private $portador = null;

    // Constructor privado: nadie puede forjar otro Anillo Único
    private function __construct() {
        echo "El Anillo Único ha sido forjado en los fuegos de Mordor.\n";
    }

    // Método estático para obtener el Anillo Único
    public static function obtenerAnillo() {
        if (self::$instancia === null) {
            self::$instancia = new self();
        }
        return self::$instancia;
    }

    // Método para reclamar el Anillo
    public function reclamar($nombre) {
        $this->portador = $nombre;
        echo "$nombre ahora es el portador del Anillo Único.\n";
    }

    // Saber quién es el portador actual
    public function verPortador() {
        return $this->portador ?? "Nadie";
    }
}

// Frodo intenta obtener el Anillo
$anillo1 = AnilloUnico::obtenerAnillo();
$anillo1->reclamar("Frodo");

// Gollum también lo quiere
$anillo2 = AnilloUnico::obtenerAnillo();
$anillo2->reclamar("Gollum");

// Ambos acceden al mismo Anillo
echo "El portador actual es: " . $anillo1->verPortador() . "\n";
echo "¿Ambos objetos son el mismo? " . ($anillo1 === $anillo2 ? "Sí" : "No") . "\n";

Salida Esperada:

El Anillo Único ha sido forjado en los fuegos de Mordor.
Frodo ahora es el portador del Anillo Único.
Gollum ahora es el portador del Anillo Único.
El portador actual es: Gollum
¿Ambos objetos son el mismo? Sí

Explicación:

  • Solo puede existir un Anillo Único: la clase solo permite una instancia.
  • Todos los personajes acceden al mismo objeto: aunque diferentes personajes reclamen el anillo, siempre es el mismo objeto.
  • El portador cambia, pero el Anillo es único: puedes ver quién es el portador actual, pero nunca habrá dos Anillos Únicos.

📄 Ejemplo real: Singleton para conexión a base de datos

<?php

class ConexionBD {
    // Propiedad estática para almacenar la instancia única
    private static $instancia = null;
    private $conexion;

    // Configuración de la base de datos
    private $host = 'localhost';
    private $db = 'mi_base_de_datos';
    private $usuario = 'usuario';
    private $contrasena = 'contrasena';

    // Constructor privado
    private function __construct() {
        try {
            $this->conexion = new PDO(
                "mysql:host={$this->host};dbname={$this->db};charset=utf8",
                $this->usuario,
                $this->contrasena
            );
            $this->conexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch (PDOException $e) {
            die("Error de conexión: " . $e->getMessage());
        }
    }

    // Método estático para obtener la instancia única
    public static function getInstancia() {
        if (self::$instancia === null) {
            self::$instancia = new self();
        }
        return self::$instancia;
    }

    // Método para obtener el objeto PDO
    public function getConexion() {
        return $this->conexion;
    }
}

// Uso del Singleton para la base de datos
$db = ConexionBD::getInstancia()->getConexion();

// Ejemplo de consulta
$stmt = $db->query("SELECT * FROM usuarios");
$usuarios = $stmt->fetchAll(PDO::FETCH_ASSOC);

print_r($usuarios);

?>

📝 Resumen de uso y ventajas

  • ¿Cuándo usarlo? Cuando necesitas una única instancia de una clase en toda la aplicación (conexión a BD, logger, configuración, etc.).
  • Ventajas: Control centralizado, ahorro de recursos, acceso global.
  • Desventajas: Puede dificultar pruebas unitarias y acoplar el código si se abusa.

Eso ha sido todo por hoy.
Nos vemos en el próximo patrón... o en la próxima frikada que se me ocurra para explicarlo 👾.