Patrón Observer
El patrón Observer define una dependencia uno-a-muchos entre objetos para que cuando uno cambie de estado, todos sus dependientes sean notificados y actualizados automáticamente. Úsalo cuando múltiples partes de tu sistema necesiten reaccionar a cambios en una única fuente de verdad.
Resumen
El patrón Observer establece un mecanismo de suscripción que permite a múltiples objetos escuchar eventos emitidos por otro objeto. El sujeto mantiene una lista de observadores y los notifica cada vez que su estado cambia, sin saber ni preocuparse por lo que esos observadores hacen con la información. Esto desacopla la fuente del cambio de los consumidores del cambio, facilitando agregar nuevas reacciones sin modificar al emisor.
Cuándo usarlo
- Un cambio en un objeto debe disparar actualizaciones en otros, y no quieres acoplamiento fuerte entre ellos.
- El número de dependientes es desconocido en tiempo de compilación o cambia en tiempo de ejecución (suscripciones dinámicas).
- Estás construyendo una arquitectura orientada a eventos — handlers de UI, brokers de mensajes, streams reactivos.
Ejemplo
interface Observer<T> {
update(data: T): void;
}
class Subject<T> {
private observers: Observer<T>[] = [];
subscribe(observer: Observer<T>) {
this.observers.push(observer);
}
unsubscribe(observer: Observer<T>) {
this.observers = this.observers.filter(o => o !== observer);
}
notify(data: T) {
this.observers.forEach(o => o.update(data));
}
}
const priceTracker = new Subject<number>();
priceTracker.subscribe({
update(price) { console.log(`Dashboard: $${price}`); }
});
priceTracker.subscribe({
update(price) {
if (price < 100) console.log('Alerta: ¡el precio bajó!');
}
});
priceTracker.notify(95);Ventajas
- Acoplamiento débil — el sujeto no sabe nada de sus observadores más allá de la interfaz.
- Se pueden agregar nuevos observadores en cualquier momento sin modificar código existente.
- Sigue el principio abierto/cerrado: abierto para extensión, cerrado para modificación.
Desventajas
- El orden de notificación no está garantizado, lo que puede causar bugs sutiles si los observadores dependen entre sí.
- Pueden ocurrir memory leaks si los observadores no se desuscriben correctamente.
- Depurar actualizaciones en cascada puede ser difícil cuando muchos observadores reaccionan al mismo evento.