Saltar al contenido

Observer

Un patrón de comportamiento: cuando un objeto cambia, los que dependen de él se enteran, sin que él tenga que conocerlos uno por uno.

7 min. de lectura

También llamado: Listener

Observer es un patrón de comportamiento que define una dependencia de uno a muchos entre objetos, de forma que cuando uno cambia, todos los que dependen de él se enteran automáticamente.

El problema

Cuando un producto de AndesShop que estaba agotado vuelve a tener stock, varias cosas tienen que reaccionar: hay que avisarle a cada usuario que se anotó en la lista de “avisame cuando esté disponible”, hay que actualizar el índice de búsqueda para que el producto vuelva a aparecer en los resultados, y hay que refrescar la caché de recomendaciones. Si el código que actualiza el stock llama directamente a cada uno de esos tres procesos, cada vez que se agregue un cuarto proceso interesado en ese evento (por ejemplo, analytics) hay que volver a modificar esa misma función — que termina sabiendo demasiado sobre quién más necesita enterarse de un cambio de stock.

La solución

Observer invierte esa dependencia: el objeto que cambia (Product) no conoce a quienes están interesados en sus cambios. En cambio, mantiene una lista de “observadores” que se suscriben a sus eventos, y simplemente les avisa a todos cuando ocurre algo relevante. Sumar un interesado nuevo es agregarlo a la lista de suscriptores, sin tocar el código de Product.

Estructura de Observer: el subject mantiene una lista de observers y les avisa sin conocer sus clases concretas. `unsubscribe` no es opcional.

Ejemplo en Java

interface StockObserver {
    void onBackInStock(Product product);
}

class Product {
    private final List<StockObserver> observers = new ArrayList<>();
    private int stock;

    public void subscribe(StockObserver observer) {
        observers.add(observer);
    }

    public void setStock(int newStock) {
        boolean wasOutOfStock = this.stock == 0;
        this.stock = newStock;
        if (wasOutOfStock && newStock > 0) {
            for (StockObserver observer : observers) {
                observer.onBackInStock(this);
            }
        }
    }
}

class WaitlistNotifier implements StockObserver {
    public void onBackInStock(Product product) {
        System.out.println("Notifying waitlist for " + product);
    }
}

class SearchIndexUpdater implements StockObserver {
    public void onBackInStock(Product product) {
        System.out.println("Re-indexing " + product + " for search");
    }
}
// Client code: sumar un interesado nuevo no toca la clase Product
Product jacket = new Product();
jacket.subscribe(new WaitlistNotifier());
jacket.subscribe(new SearchIndexUpdater());

jacket.setStock(10); // dispara ambas reacciones, sin que Product las conozca

Cuándo usarlo

  • Cuando un cambio en un objeto necesita disparar reacciones en un número variable de otros objetos, que se conocen recién en tiempo de ejecución.
  • Cuando querés evitar que el objeto que cambia dependa directamente de todos los que reaccionan a su cambio.

Cuándo evitarlo

Si el orden en que se notifica a los observadores importa y es rígido, o si necesitás garantías estrictas de que la notificación se procesó antes de continuar, un mecanismo de eventos simple puede no alcanzar — vale la pena evaluar una cola de mensajes o un mecanismo más explícito.

Ventajas y desventajas

VentajasDesventajas
Desacopla al objeto que cambia de quienes reaccionan a ese cambioEl orden de notificación entre observadores no siempre es predecible ni controlable
Permite agregar o quitar observadores en tiempo de ejecuciónUn observador que falla puede afectar a los demás si no se maneja con cuidado
Sigue el principio de abierto/cerrado: sumar un interesado nuevo no modifica al que cambiaSi hay muchos observadores encadenados entre sí, puede ser difícil rastrear el flujo completo de reacciones

Relación con otros patrones

  • Mediator también reduce dependencias entre objetos, pero centraliza toda la coordinación; Observer solo notifica eventos de uno a muchos, sin que el emisor decida cómo reaccionan.
  • Es la base conceptual detrás de mecanismos de eventos y de programación reactiva más generales.

Te sirvió, compartilo

// ¿te sirvió?
// compartilo