: El patrón de observador

En JavaScript, hay un problema que aparece a menudo. Necesita una forma de actualizar partes de una página en respuesta a ciertos eventos, con los datos que proporcionan. Digamos, por ejemplo, la entrada de usuario que luego proyecta en uno o varios componentes. Esto lleva a una gran cantidad de push-and-pull en el código para mantener todo sincronizado.

Aquí es donde el patrón de diseño del observador puede ayudar: habilita el enlace de datos de uno a muchos entre elementos. Este enlace de datos unidireccional puede ser impulsado por eventos. Con este patrón, puede crear código reutilizable que resuelva sus necesidades específicas.

En este artículo, me gustaría explorar el patrón de diseño del observador. Le ayudará a resolver un problema común que ve en los scripts del lado del cliente. Es un enlace de datos de uno a muchos, unidireccional y basado en eventos. Es un problema que surge a menudo cuando tienes muchos elementos que deben estar sincronizados.

Usaré ECMAScript 6 para ilustrar el patrón. Sí, habrá clases, funciones de flecha y constantes. Siéntase libre de explorar estos temas por su cuenta si aún no está familiarizado. Usaré partes de ES6 que solo introducen azúcar sintáctico, por lo que es portátil con ES5 si es necesario.

Y usaré Desarrollo basado en pruebas (TDD) para trabajar en el patrón. De esta manera, tiene una manera de saber cómo cada componente es útil.

Las nuevas funciones de idioma de ES6 crean un código sucinto. Así que empecemos.

El Observador de eventos

Una vista de alto nivel del patrón se ve así:

EventObserver│ ├── subscribe: adds new observable events│ ├── unsubscribe: removes observable events|└── broadcast: executes all events with bound data

Después de completar el patrón de observador, agregaré un recuento de palabras que lo use. El componente de conteo de palabras tomará a este observador y lo unirá todo.

Para inicializar el EventObserver do:

class EventObserver { constructor() { this.observers = ; }}

Comience con una lista vacía de eventos observados y haga esto para cada instancia nueva. A partir de ahora, agreguemos más métodos dentro de EventObserver para desarrollar el patrón de diseño.

El Método Subscribe

Para añadir nuevos eventos:

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

Coge la lista de eventos observados y empujar un nuevo elemento a la matriz. La lista de eventos es una lista de funciones de devolución de llamada.

Una forma de probar este método en JavaScript simple es la siguiente:

// Arrangeconst observer = new EventObserver();const fn = () => {};// Actobserver.subscribe(fn);// Assertassert.strictEqual(observer.observers.length, 1);

Utilizo aserciones de nodo para probar este componente en el nodo. También existen las mismas afirmaciones que las afirmaciones de Chai.

Nota la lista de eventos observados consiste en devoluciones de llamada de humble. Luego comprobamos la longitud de la lista y afirmamos que la devolución de llamada está en la lista.

El Método de cancelación de suscripción

Para eliminar eventos:

unsubscribe(fn) { this.observers = this.observers.filter((subscriber) => subscriber !== fn);}

Filtra de la lista lo que coincida con la función de devolución de llamada. Si no hay coincidencia, la devolución de llamada se queda en la lista. El filtro devuelve una nueva lista y reasigna la lista de observadores.

Para probar este buen método, haga:

// Arrangeconst observer = new EventObserver();const fn = () => {};observer.subscribe(fn);// Actobserver.unsubscribe(fn);// Assertassert.strictEqual(observer.observers.length, 0);

La devolución de llamada debe coincidir con la misma función que está en la lista. Si hay una coincidencia, el método de cancelación de suscripción la elimina de la lista. Nota: la prueba utiliza la referencia de función para agregarla y eliminarla.

El método de difusión

Para llamar a todos los eventos:

broadcast(data) { this.observers.forEach((subscriber) => subscriber(data));}

Esto itera a través de la lista de eventos observados y ejecuta todas las devoluciones de llamada. Con esto, obtienes la relación necesaria de uno a muchos con los eventos suscritos. Se pasa el parámetro data que hace que los datos de devolución de llamada estén enlazados.

ES6 hace que el código sea más efectivo con una función de flecha. Observe la función (subscriber) => subscriber(data) que hace la mayor parte del trabajo. Esta función de flecha de un solo trazador se beneficia de esta sintaxis ES6 corta. Esta es una mejora definitiva en el lenguaje de programación JavaScript.

Para probar este método de difusión, haga:

// Arrangeconst observer = new EventObserver();let subscriberHasBeenCalled = false;const fn = (data) => subscriberHasBeenCalled = data;observer.subscribe(fn);// Actobserver.broadcast(true);// Assertassert(subscriberHasBeenCalled);

Use let en lugar de const para que podamos cambiar el valor de la variable. Esto hace que la variable sea mutable, lo que me permite reasignar su valor dentro de la devolución de llamada. El uso de un let en su código envía una señal a otros programadores de que la variable está cambiando en algún momento. Esto añade legibilidad y claridad a su código JavaScript.

Esta prueba me da la confianza necesaria para asegurar que el observador está trabajando como espero. Con TDD, se trata de crear código reutilizable en JavaScript simple. Hay beneficios al escribir código comprobable en JavaScript plano. Pruebe todo y conserve lo que es bueno para reutilizar el código.

Con esto, hemos desarrollado el EventObserver. La pregunta es, ¿qué se puede construir con esto?

El patrón del Observador en Acción: Una Demostración de Recuento de palabras de Blog

Para la demostración, es hora de poner en marcha una publicación de blog donde mantenga el recuento de palabras por usted. Cada pulsación de tecla que ingrese como entrada se sincronizará con el patrón de diseño del observador. Piense en ello como una entrada de texto libre donde cada evento dispara una actualización a donde necesita ir.

Para obtener un recuento de palabras de la entrada de texto libre, se puede hacer:

const getWordCount = (text) => text ? text.trim().split(/\s+/).length : 0;

¡Hecho! Hay mucho que hacer en esta función aparentemente simple y pura, así que, ¿qué tal una humilde prueba unitaria? De esta manera queda claro lo que pretendía hacer con esto:

// Arrangeconst blogPost = 'This is a blog \n\n post with a word count. ';// Actconst count = getWordCount(blogPost);// Assertassert.strictEqual(count, 9);

Tenga en cuenta la cadena de entrada algo loca dentro de blogPost. Pretendo que esta función cubra tantos casos extremos como sea posible. Mientras me dé un recuento adecuado de palabras, de hecho, vamos en la dirección correcta.

Como nota al margen, este es el poder real de TDD. Se puede iterar sobre esta implementación y cubrir tantos casos de uso como sea posible. La prueba unitaria te dice cómo espero que se comporte esto. Si el comportamiento tiene un defecto, por cualquier motivo, es fácil iterarlo y modificarlo. Con la prueba, queda suficiente evidencia para que cualquier otra persona pueda hacer cambios.

Tiempo para conectar estos componentes reutilizables al DOM. Esta es la parte en la que puedes usar JavaScript simple y soldarlo directamente en el navegador.

Una forma de hacerlo sería tener el siguiente HTML en la página:

<textarea placeholder="Enter your blog post..." class="blogPost"></textarea>

Seguido por este JavaScript:

const wordCountElement = document.createElement('p');wordCountElement.className = 'wordCount';wordCountElement.innerHTML = 'Word Count: <strong>0</strong>';document.body.appendChild(wordCountElement);const blogObserver = new EventObserver();blogObserver.subscribe((text) => { const blogCount = document.getElementById('blogWordCount'); blogCount.textContent = getWordCount(text);});const blogPost = document.getElementById('blogPost');blogPost.addEventListener('keyup', () => blogObserver.broadcast(blogPost.value));

Tome todo su código reutilizable y coloque el patrón de diseño del observador. Esto hará un seguimiento de los cambios en el área de texto y le dará un recuento de palabras justo debajo de él. Estoy usando body.appendChild() en la API DOM para agregar este nuevo elemento. Luego, adjuntando los oyentes del evento para darle vida.

Nota con las funciones de flecha es posible conectar eventos de un solo revestimiento. De hecho, puedes transmitir cambios impulsados por eventos a todos los suscriptores con esto. El () => blogObserver.broadcast() hace la mayor parte del trabajo aquí. Incluso pasa los últimos cambios al área de texto directamente a la función de devolución de llamada. Sí, los scripts del lado del cliente son súper geniales.

Ninguna demostración está completa sin una que pueda tocar y ajustar, a continuación se muestra el CodePen:

Vea el Patrón de Observador de Lápiz de SitePoint (@SitePoint) en CodePen.

Ahora, no llamaría a esta función completa. No es más que un punto de partida del patrón de diseño del observador. La pregunta en mi mente es, ¿hasta dónde estás dispuesto a llegar?

Mirando hacia el futuro

Depende de usted llevar esta idea aún más lejos. Hay muchas maneras de utilizar el patrón de diseño del observador para crear nuevas características.

Puede mejorar la demostración con:

  • Otro componente que cuenta el número de párrafos
  • Otro componente que muestra una vista previa del texto introducido
  • Mejore la vista previa con compatibilidad con reducción de precios, por ejemplo

Estas son solo algunas ideas que puede hacer para profundizar en esto. Las mejoras anteriores desafiarán sus habilidades de programación.

Conclusión

El patrón de diseño del observador puede ayudarlo a resolver problemas del mundo real en JavaScript. Esto resuelve el problema perenne de mantener un grupo de elementos sincronizados con los mismos datos. Como suele ser el caso, cuando el navegador dispara eventos específicos. Estoy seguro de que la mayoría de ustedes ya se han encontrado con este problema y han corrido hacia herramientas y dependencias de terceros.

Este patrón de diseño te equipa para ir tan lejos como tu imaginación esté dispuesta a ir. En la programación, abstrae la solución en un patrón y crea código reutilizable. No hay límite a lo lejos que esto te llevará.

Espero que veas cuánto, con un poco de disciplina y esfuerzo, puedes hacer en JavaScript simple. Las nuevas características del lenguaje, como ES6, le ayudan a escribir un código sucinto que es reutilizable.

Este artículo fue revisado por pares por Giulio Mainardi. ¡Gracias a todos los revisores de pares de SitePoint por hacer que el contenido de SitePoint sea lo mejor que puede ser!

Deja una respuesta

Tu dirección de correo electrónico no será publicada.