Skip to content
SP StackPractices
beginner

Patrón Observer

Define un mecanismo de suscripción para notificar a múltiples objetos sobre eventos. Patrón de diseño conductual para comunicación basada en eventos.

Temas: design

Patrón Observer

Visión general

El Patrón Observer es un patrón de diseño conductual que define un mecanismo de suscripción para notificar a múltiples objetos sobre eventos que ocurren en el objeto que están observando. Establece una dependencia uno-a-muchos entre objetos.

Es la base de arquitecturas basadas en eventos, programación reactiva y la arquitectura Model-View en frameworks de UI.

Cuándo usarlo

Usa el Patrón Observer cuando:

  • Los cambios en un objeto requieren actualizar un número desconocido de objetos dependientes
  • Necesitas un modelo de comunicación publicar-suscribir
  • Un objeto debe notificar a otros sin saber quiénes son
  • Quieres acoplamiento débil entre productores y consumidores de eventos
  • Construyes componentes de UI reactivos o feeds de datos en tiempo real

Solución

Python

class Subject:
    def __init__(self):
        self._observers = []

    def attach(self, observer):
        self._observers.append(observer)

    def notify(self, data):
        for observer in self._observers:
            observer.update(data)

class Observer:
    def update(self, data):
        print(f"Recibido: {data}")

# Uso
subject = Subject()
subject.attach(Observer())
subject.attach(Observer())
subject.notify("¡Hola observadores!")

JavaScript

class Subject {
  constructor() {
    this.observers = [];
  }

  subscribe(fn) {
    this.observers.push(fn);
  }

  notify(data) {
    this.observers.forEach((fn) => fn(data));
  }
}

// Uso
const subject = new Subject();
subject.subscribe((data) => console.log("A:", data));
subject.subscribe((data) => console.log("B:", data));
subject.notify("¡Hola observadores!");

Java

import java.util.ArrayList;
import java.util.List;

interface Observer {
    void update(String data);
}

class Subject {
    private final List<Observer> observers = new ArrayList<>();

    void attach(Observer o) {
        observers.add(o);
    }

    void notifyObservers(String data) {
        for (Observer o : observers) {
            o.update(data);
        }
    }
}

// Uso
Subject subject = new Subject();
subject.attach(data -> System.out.println("Recibido: " + data));
subject.notifyObservers("¡Hola observadores!");

Explicación

El Patrón Observer consiste en dos roles principales:

  • Subject (Publicador): Mantiene una lista de observadores y envía notificaciones
  • Observer (Suscriptor): Define una interfaz para objetos que deben ser notificados de cambios

Cuando el estado del Subject cambia, itera sobre sus observadores y llama su método update. Los observadores pueden suscribirse o darse de baja dinámicamente sin que el Subject conozca las clases concretas.

Variantes

VarianteCaso de usoCompromiso
Modelo pushEl subject envía datos completos a observadoresSimple, pero puede enviar datos innecesarios
Modelo pullEl subject notifica; los observadores consultan detallesMás eficiente, pero añade idas y vueltas
Event busUn despachador central desacopla subjects y observersMás flexible, añade indirección

Mejores prácticas

  • Desuscríbete de observadores cuando se destruyen para prevenir fugas de memoria
  • Evita actualizaciones circulares donde observadores disparan cambios de vuelta al subject
  • Usa referencias débiles en lenguajes que lo soportan (ej. Java) para limpieza automática
  • Mantén la lógica de notificación simple y evita cómputos pesados en el loop de notify
  • Documenta los payloads de eventos para que los observadores sepan qué datos esperar

Errores comunes

  • Fugas de memoria: Olvidar desvincular observadores cuando ya no se necesitan
  • Orden de actualización inesperado: Los observadores pueden ejecutarse en orden indefinido; no dependas de ello
  • Bucles infinitos: Un observador que modifica el subject puede desencadenar actualizaciones en cascada
  • Acoplamiento fuerte: Dar a los observadores acceso al subject completo en lugar de solo los datos que necesitan
  • Bloqueo síncrono: Ejecutar observadores lentos en el hilo principal de notificación

Preguntas frecuentes

P: ¿Cuál es la diferencia entre Observer y Pub/Sub? R: Observer es una relación directa subject-observer. Pub/Sub añade un broker de eventos (event bus) que desacopla completamente a los publicadores de los suscriptores.

P: ¿Sigue siendo relevante el Patrón Observer con frameworks reactivos modernos? R: Sí. React hooks, RxJS y el sistema de reactividad de Vue están construidos sobre conceptos de Observer.

P: ¿Cómo evito fugas de memoria con observadores? R: Siempre proporciona un mecanismo de desuscripción y llámalo en manejadores de limpieza o destructores.