🚨 ¡Nueva review! 🔇 Los mejores cascos con ANC del mercado: los Sony WH-1000XM4 . ¡Échale un ojo! 👀

El Patrón de Diseño Observer

El sistema de suscripciones para tu código

Escrito por domin el 16 de noviembre de 2025

🔔 El Patrón Observer: El gran sistema de notificaciones

El Patrón Observer pertenece a la familia de los patrones de comportamiento y resuelve un problema muy común: ¿Cómo haces que muchos objetos reaccionen a los cambios de otro objeto, pero sin que este objeto principal tenga que saber quiénes son?

El objetivo principal de Observer es establecer una relación de dependencia uno-a-muchos entre objetos, de tal forma que cuando el objeto principal (el sujeto) cambia de estado, todos sus objetos dependientes (los observadores) son notificados y actualizados automáticamente.

La respuesta es crear una suscripción. El Sujeto tiene una lista de Observadores a los que notifica un evento. Esto hace que el código esté desacoplado: el Sujeto no tiene ni idea de qué hacen los Observadores con el cambio, solo sabe que tiene que avisarles.

Diagrama del Patrón Observer mostrando un Sujeto que notifica automáticamente a múltiples Observadores cada vez que ocurre un cambio de estado.

🔔 1. Un ejemplo sencillo: El famoso y sus fans

Imagina una estrella de cine o un famoso de la prensa rosa:

Concepto (analogía)

Rol en Observer

Tarea principal

La Estrella de Cine/El Famoso

Sujeto (Observable)

Guarda la lista de Observadores, permite suscribir/desuscribir, y los notifica de los cambios.

Las Revistas/Los Fans

Observador

Se suscribe al Sujeto y define la lógica para reaccionar al ser notificado (método update).

El secreto está en que el Sujeto (Famoso) solo tiene que implementar un mecanismo para notificar a una lista de objetos genéricos (Observadores). Le da igual si es una revista, un fan o un programa de televisión, lo cual es la clave del desacoplamiento.

🛠️ 2. Los tres pilares del patrón Observer

El Observer necesita tres roles principales para funcionar correctamente:

1. El Sujeto (Observable)

2. El Observador

3. Los Observadores Concretos

✨ Widget Pedagógico: El Interruptor de Notificación

Imagina que el Sujeto tiene un interruptor. Cuando el interruptor se enciende (cambio de estado), todos los Observadores conectados por cable se encienden al mismo tiempo. Al Sujeto le da igual si un Observador es una bombilla o un altavoz (la lógica del update), solo sabe que tiene que mandar electricidad (la notificación).

🤔 1. ¿Cuál es el principal objetivo del Patrón Observer?

📝 3. El ejemplo clásico: Un Blog y sus suscriptores

Imagina que tienes un blog. Cuando publicas un nuevo post, quieres notificar automáticamente a tres tipos de suscriptores: los Usuarios por Email, la Cuenta de Twitter, y un Sistema de Log.

Clase/RolFunción (Ej. update)
Blog Post SujetoGuarda el nuevo título del post. Notifica a todos al publicarse.
Observador por EmailRecibe la notificación y envía el email al usuario.
Observador de TwitterRecibe la notificación y publica el tweet.

Clase/Rol

Función (Ej. update)

Sujeto (Blog Post)

Llama al método update() de todos los suscritos con el título del nuevo post. No sabe si están enviando un email o un tweet.

Observador Concreto

Cada uno implementa su propia reacción al evento. Por ejemplo, si mañana añades un Observador de WhatsApp, el Sujeto no tiene que cambiar.

¡El Blog Post Sujeto está totalmente desacoplado de sus acciones! Si se añade una nueva red social, solo hay que crear un nuevo Observador y suscribirlo. El código del Sujeto permanece limpio y sin cambios.

🤔 2. ¿Qué métodos esenciales debe tener el Sujeto (Observable)?

✅ 4. ¿Por qué usarlo?

El Observer es un patrón clave en la programación orientada a eventos:

  1. Desacoplamiento: Es el beneficio clave. El Sujeto y el Observador pueden cambiar de forma independiente. Si añades o quitas un Observador, el Sujeto no se entera.
  2. Flexibilidad: Es muy fácil añadir nuevas funcionalidades (nuevos Observadores) sin modificar el código que ya funciona (el Sujeto).
  3. Sistema de Broadcasting: Permite la comunicación uno-a-muchos de forma eficiente. Cuando se lanza un evento, todos los interesados son notificados al instante.
  4. Patrón Común: Es la base de muchos sistemas: frameworks MVC, event listeners de JavaScript, y la programación reactiva.

❌ 5. Desventaja a considerar

🤔 3. ¿Por qué se dice que el Patrón Observer logra el desacoplamiento?

💡 6. Conclusión

El Patrón Observer es una herramienta esencial cuando necesitas que muchas partes de tu aplicación reaccionen a un evento único en un lugar centralizado. Es el patrón que te permite crear sistemas de eventos robustos y escalables, como un sistema de widgets en un dashboard o la gestión de notificaciones de una API.

Si quieres evitar el código espagueti donde tienes que llamar a 10 funciones distintas cada vez que un dato importante cambia, implementa el Observer para conseguir un código limpio y flexible.

🧠 7. Ejemplo Práctico en PHP

Vamos a implementar el patrón Observer con el ejemplo de la publicación de un post en un blog. El Sujeto será el Blog y los Observadores serán diferentes sistemas de notificación.

<?php

// 🔹 1. La Interfaz del Observador
interface Observador {
    // Este método es llamado por el Sujeto cuando su estado cambia.
    public function update(string $mensaje): void;
}

// 🔹 2. La Interfaz del Sujeto (Observable)
interface Sujeto {
    public function attach(Observador $observador): void;
    public function detach(Observador $observador): void;
    public function notify(): void;
}

// --- OBSERVADORES CONCRETOS (La reacción al cambio) ---

// El Observador que envía un email.
class NotificadorEmail implements Observador {
    public function update(string $mensaje): void {
        echo "   [EMAIL] Enviado: Nuevo Post - \"$mensaje\"." . PHP_EOL;
    }
}

// El Observador que publica en una red social.
class NotificadorRedSocial implements Observador {
    public function update(string $mensaje): void {
        echo "   [TWITTER] Publicado: ¡Mira nuestro nuevo post! \"$mensaje\"." . PHP_EOL;
    }
}

// El Observador que simplemente registra el evento.
class NotificadorLog implements Observador {
    public function update(string $mensaje): void {
        echo "   [LOG] Registrado en el sistema: Post publicado - \"$mensaje\"." . PHP_EOL;
    }
}

// --- EL SUJETO CONCRETO (El objeto que tiene el estado que interesa) ---

class Blog implements Sujeto {
    private array $observadores = [];
    private string $ultimoPost = "";

    /**
     * Permite a un Observador suscribirse a la lista.
     */
    public function attach(Observador $observador): void {
        $this->observadores[] = $observador;
        echo "   [BLOG] Nuevo observador suscrito: " . get_class($observador) . PHP_EOL;
    }

    /**
     * Permite a un Observador desuscribirse de la lista.
     */
    public function detach(Observador $observador): void {
        // En un caso real usaríamos una clave única para eliminarlo fácilmente.
        // Aquí simplemente mostramos que se ha desuscrito.
        echo "   [BLOG] Observador desuscrito: " . get_class($observador) . PHP_EOL;
    }

    /**
     * Recorre la lista y notifica a todos los Observadores.
     */
    public function notify(): void {
        echo "   [BLOG] Notificando a " . count($this->observadores) . " observadores..." . PHP_EOL;
        foreach ($this->observadores as $observador) {
            $observador->update($this->ultimoPost);
        }
    }

    /**
     * El método que simula el cambio de estado.
     */
    public function publicarNuevoPost(string $titulo): void {
        $this->ultimoPost = $titulo;
        echo PHP_EOL . "--- EVENTO: Publicando nuevo post: \"$titulo\" ---" . PHP_EOL;
        // Cuando el estado cambia, el Blog notifica a sus suscriptores.
        $this->notify();
    }
}


// 🔹 4. Uso del patrón (El Cliente)
$blog = new Blog();

// Creamos los observadores.
$email = new NotificadorEmail();
$twitter = new NotificadorRedSocial();
$log = new NotificadorLog();

// Suscribimos a los interesados.
echo "--- Proceso de Suscripción ---" . PHP_EOL;
$blog->attach($email);
$blog->attach($twitter);
$blog->attach($log);

// Simulamos la publicación de un post (el evento que cambia el estado).
$blog->publicarNuevoPost("El Patrón Observer: La clave del desacoplamiento");

// Un observador se desuscribe (por ejemplo, el sistema de log ya no lo necesita).
echo PHP_EOL . "--- Un Observador se Desuscribe ---" . PHP_EOL;
$blog->detach($log);

// Simulamos otra publicación. El NotificadorLog ya no será avisado.
$blog->publicarNuevoPost("Astro JS y los Patrones de Diseño");

// 🖥️ Salida del programa:
// --- Proceso de Suscripción ---
//    [BLOG] Nuevo observador suscrito: NotificadorEmail
//    [BLOG] Nuevo observador suscrito: NotificadorRedSocial
//    [BLOG] Nuevo observador suscrito: NotificadorLog
//
// --- EVENTO: Publicando nuevo post: "El Patrón Observer: La clave del desacoplamiento" ---
//    [BLOG] Notificando a 3 observadores...
//    [EMAIL] Enviado: Nuevo Post - "El Patrón Observer: La clave del desacoplamiento".
//    [TWITTER] Publicado: ¡Mira nuestro nuevo post! "El Patrón Observer: La clave del desacoplamiento".
//    [LOG] Registrado en el sistema: Post publicado - "El Patrón Observer: La clave del desacoplamiento".
//
// --- Un Observador se Desuscribe ---
//    [BLOG] Observador desuscrito: NotificadorLog
//
// --- EVENTO: Publicando nuevo post: "Astro JS y los Patrones de Diseño" ---
//    [BLOG] Notificando a 2 observadores...
//    [EMAIL] Enviado: Nuevo Post - "Astro JS y los Patrones de Diseño".
//    [TWITTER] Publicado: ¡Mira nuestro nuevo post! "Astro JS y los Patrones de Diseño".

EA, ¡saluditos y nos vemos en los bares! 🍻