El patrón de observador en JavaScript: la clave para un comportamiento reactivo

El patrón de observador en JavaScript: la clave para un comportamiento reactivo

@programacion
https://unsplash.com/photos/jdTdvF6fDus

Muchos desarrolladores nuevos tienden a agregar un velo de magia frente a marcos como React debido a la forma en que ven el flujo de datos y cuán diferente es de todo lo que aprendieron mientras se convertían en desarrolladores nuevos.

Y es cierto, es como magia si no sabes lo que está pasando, pero como dijo una vez Arthur C. Clarke:

Cualquier tecnología suficientemente avanzada es indistinguible de la magia

Así que echemos un vistazo más de cerca al principio básico detrás de cualquier comportamiento reactivo que pueda encontrar en la naturaleza y por qué (a) no es mágico, y (b) es tan útil de entender.

Eso sí, no voy a fingir y simplificar en exceso React a un solo patrón le permitirá comprender cómo funciona todo el marco. Solo estoy hablando de un principio único que se puede usar en múltiples casos de uso, uno de ellos es un marco de trabajo frontal.

El patrón del observador explicado

Comencemos por el principio: lo primero que debe comprender es el patrón en sí.

Y confía en mí, una vez que lo hagas, verás que no hay magia en absoluto (¡perdón por reventar tu burbuja!).

Esto es lo que se conoce como “patrón de comportamiento” en el sentido de que trata sobre el comportamiento de los objetos y cómo interactúan entre sí cuando algo sucede.

Dicho esto, el patrón muestra cómo estructurar un tipo de relación observador-observado cuando un conjunto de objetos (los observadores) están interesados ​​en cualquier tipo de cambio en el estado de otro objeto único (el observado).

Sin embargo, la clave aquí es que los "observadores" no observan activamente el objeto observado, sino que se suscriben para recibir notificaciones y permiten que el elemento observado les notifique una vez que sucede algo.

Y ese pequeño detalle es crucial, porque si lo observa activamente, significa que tiene que pasar ciclos computacionales realizando algún tipo de verificación. Y si bien esto puede no parecer gran cosa para un solo objeto, si aumenta la escala a cientos (o potencialmente miles) de observadores, el tiempo requerido se vuelve significativo. Así que sí, es un problema.

Si, en cambio, esos observadores son libres de seguir trabajando, o simplemente permanecer inactivos mientras esperan sin gastar ciclos de procesamiento, entonces el patrón se convierte en un sueño de desempeño.

Si todavía tiene dificultades, piense en ello como ir usted mismo a buscar su periódico diario en lugar de suscribirse y recibirlo en su puerta. Gastará mucha más energía y tiempo yendo allí todos los días en lugar de esperar a que se lo entreguen.

El diagrama anterior no es un intento de un UML del patrón (¡los estoy mirando puristas!), sino un ejemplo simple de cómo 3 observadores interactuarían con el objeto observado. Es así de simple. Puede ver cómo desde fuera cada observador llamaría al addSubscribermétodo y cómo el notifySubscribersmétodo llamaría a su updatemétodo, con un eventparámetro específico. El evento no es más que los detalles de lo que acaba de cambiar. Podría cambiar esto y, en su lugar, permitir que los observadores accedan directamente al estado del objeto observado, pero creo que de esta manera es mucho más fácil ya que les muestra específicamente qué cambió (es decir, qué activó la notificación).

Ahora puede comenzar a ver que no hay magia real detrás de este patrón, es tan elegante que desde el punto de vista del observador (que en algunas situaciones es donde se encuentra el desarrollador) parece mágico.

Implementando el patrón de observador en JavaScript

¡Ensuciémonos las manos ahora con algo de código!

Para este ejemplo, voy a fingir que tenemos algún tipo de ciclo en el que estamos iterando el valor de una variable y queremos reaccionar cuando el valor cumple con ciertos criterios.

Por ejemplo, imagine tener un bucle del 1 al 1000 y querer asegurarse de que reaccionamos ante cada número impar. Siguiendo lo que he estado diciendo hasta ahora, terminarías con algo como esto:

Ahora, estamos tratando con JavaScript aquí, por lo que debemos recordar que no existe el concepto (al menos no todavía) de métodos o propiedades "privados", o incluso de clases o métodos abstractos. Así que tendremos que jugar de oído al implementarlos.

Sin embargo, podemos implementar algo que nos permita trabajar así:

Implementación muy sencilla, pero entiendes el punto. La clase Lopper tomará el inicio y el final del bucle y lo ejecutará con el método run. Y antes de eso podemos insertar tantos observadores como queramos a través del método addObserver. La lógica requerida para entender CUÁNDO y CÓMO reaccionará el observador está encapsulada dentro de cada observador (en este caso, OddNotifier).

Ejecutar este código produciría una salida como la siguiente:

Como puede ver, hemos implementado un observador muy molesto.

Así que echemos un vistazo a esa lógica ahora:

Como puede ver, hemos vuelto a implementar los métodos eventIsRelevantreactToEventque también se definieron (según nuestro diagrama UML) en la clase principal Observer. Aquí estamos comprobando claramente el nombre del evento y el valor. Si coincide con nuestros criterios, devolvemos verdadero. Sin embargo, observe cómo no estamos implementando el método update aquí. No será necesario sobrescribirlo, ya que una implementación básica como parte de la clase principal será suficiente. La clase de padres se encargará de llamar al reactToEventsi corresponde. Echemos un vistazo rápido a eso ahora:

Nada demasiado sofisticado aquí, he definido un método update muy simple que recibe un evento y, si es relevante, reaccionará ante él. Lo que sea que eso signifique se deja que cada observador concreto lo defina (como ya hemos visto).

En cuanto al tema de nuestra atención, nuestra clase Looper, se encargará de iterar sobre los valores, como dicta su lógica muy complicada, y cada vez que se deba desencadenar un nuevo evento, notificará a los observadores. Echar un vistazo:

El código no se preocupa por cómo agregar nuevos observadores o qué significa notificarlos. Solo necesita saber que hay un método llamado notifyObserversy que debe llamarse en cada evento relevante. En este caso, eso se traduce como "en cada nuevo valor de mi bucle". Pero podría ser cualquier otra cosa en realidad. De hecho, si la lógica fuera más compleja, también podríamos desencadenar múltiples eventos y, dependiendo de la lógica dentro de cada observador concreto, podrían decidir si el evento es relevante o no para ellos.

Finalmente, la clase Subject es muy sencilla, ya que solo debe preocuparse de recolectar y notificar a los observadores:

No hay nada más simple que eso para ser honesto.

Ahora, vayamos un poco más allá e intentemos mostrar un ejemplo que le resulte más familiar, especialmente si es un desarrollador de React.

Imagina que pudieras hacer algo como esto:

He creado un "Hooks", que establece el estado inicial de nuestra variable looperen 1, y también devuelve una función para aumentarlo en 1 cada vez. Además de nuestra capacidad para aumentar el estado de nuestro looper interno en 1, ¿crees que tengo todo lo que necesito para que esta "magia" funcione?

Porque funciona:

Aquí está nuestro Hooks implementado:

No es demasiado extraño ahora que entendemos el patrón, ¿verdad? Y el nuevo método increase no es más que esto:

Estoy actualizando el estado interno y notificando a todos los observadores. Eso es todo lo que necesitábamos.

Ahora que se revela el "Veil" del patrón del observador y el comportamiento místico de los "Hooks" no es más que un conjunto preestablecido de observadores. ¿Qué piensa usted al respecto?

¿Habías usado este patrón antes? ¿Lo has probado con el eventEmitterde Node.js? ¡Eso hace que sea aún más fácil de implementar, ya que ese módulo está haciendo todo el trabajo pesado por nosotros!

Fuente:

https://blog.bitsrc.io/the-observer-pattern-in-javascript-the-key-to-a-reactive-behavior-f28236e50e10


Report Page