Observer Pattern para filtros reactivos en JS

Resumen

El Observer Pattern es uno de los patrones de diseño más usados en JavaScript para lograr programación reactiva sin caer en código espagueti. Si estás construyendo interfaces que responden a cambios de estado, como filtros dinámicos en un formulario, este patrón te permite suscribir funciones a un observable y notificar automáticamente cuando algo cambia.

¿Por qué usar el Observer Pattern para filtros reactivos?

Cuando trabajas con un formulario que aplica filtros sobre un array, lo más intuitivo es ejecutar la función de renderizado dentro del evento click. Pero eso acopla la lógica de UI con la lógica de datos. Con el patrón observador, escuchas cambios en el estado del filtro y reaccionas de forma desacoplada.

La idea central es simple: en lugar de llamar directamente a la función que actualiza la vista, los elementos interesados se suscriben a los cambios, y cuando algo se modifica, el observable notifica a todos los suscriptores.

¿Qué es el Observer Pattern? Es un patrón de diseño donde un objeto (observable) mantiene una lista de funciones suscritas y las ejecuta automáticamente cada vez que su estado cambia. Reduce el acoplamiento entre eventos y renderizado.

¿Cómo se estructura el patrón observador paso a paso?

El recurso patterns.dev [3:20] es una referencia excelente para aprender patrones de desarrollo web, con explicaciones gráficas, videos y versión en ebook. Ahí encuentras la definición canónica del patrón, que se compone de tres piezas clave:

  • Un array privado de observers que almacena las funciones suscritas.
  • Un método subscribe que recibe una función y la agrega al array con push.
  • Un método unsubscribe que usa filter para remover la función sin mutar el array.
  • Un método notify que itera todos los observers y ejecuta cada función pasándole la data actual.

Un detalle importante: para desuscribir no se usa splice, se usa filter. ¿La razón? filter devuelve un nuevo array y reasigna, evitando mutaciones y respetando la inmutabilidad.

¿Cómo aplicar el patrón a una clase FilterState?

En el ejemplo trabajamos con una clase FilterState que administra cuatro estados de filtro:

  • frequency: frecuencia del filtro.
  • status: estado activo o inactivo.
  • minimum: mínimo de elementos seguidos.
  • search: búsqueda por texto.

La clase incluye métodos básicos de programación orientada a objetos: devolver el estado, modificar un filtro específico, actualizar todo el estado con spread operator y un reset para volver al estado inicial. Sobre esa base se monta el patrón observador.

Dentro de la clase declaras un array privado #observers = []. Luego agregas los métodos:

javascript subscribe(observerFunction) { this.#observers.push(observerFunction); }

unsubscribe(observerFunction) { this.#observers = this.#observers.filter(obs => obs !== observerFunction); }

notify() { this.#observers.forEach(observerFunction => observerFunction(this.filters)); }

Fíjate que en notify puedes decidir si pasar la data explícitamente o simplemente enviar el estado actual de los filtros. Ambas opciones son válidas, pero como toda la clase gira alrededor del estado de filtros, tiene sentido enviarlo directamente.

¿Dónde se usa el Observer Pattern en el mundo real?

Este patrón lleva mucho tiempo existiendo en el ecosistema de JavaScript, aunque no era nativo. Con las nuevas propuestas de ECMAScript [8:50], ya existe un constructor Observable nativo para implementarlo sin escribir la carcasa manualmente.

¿Cuándo conviene usar el Observer Pattern? Cuando manejas reactividad, flujos de datos en tiempo real, streaming, chats o cualquier interfaz que responda a múltiples fuentes de cambio simultáneas.

Una librería que lleva este patrón a otro nivel es RxJS, disponible no solo para JavaScript sino también para Java y Go. Netflix la usa intensamente para procesar streaming de video en tiempo real, tanto en backend como en el navegador. Si tu camino apunta al front end moderno, tarde o temprano te vas a cruzar con estos conceptos.

¿Qué métodos de array sostienen este patrón?

Lo interesante es que aunque el observador suena avanzado, se construye con métodos convencionales que ya conoces:

  • push para agregar suscriptores al array.
  • filter para desuscribir sin mutar.
  • forEach dentro de notify para iterar y ejecutar cada función.

¿Por qué usar filter en lugar de splice? Porque filter retorna un nuevo array y respeta la inmutabilidad, mientras que splice muta el array original y puede generar efectos secundarios difíciles de rastrear.

Con la carcasa lista, el siguiente paso es conectar este observable a la lógica de negocio de los filtros y ver cómo el subscribe cobra sentido dentro de la interfaz. ¿Ya habías usado este patrón antes? Cuéntame en los comentarios cómo lo aplicaste.