modele de design JavaScript: Modelul Observer

în JavaScript, există o problemă care apare adesea. Aveți nevoie de o modalitate de a actualiza părți ale unei pagini ca răspuns la anumite evenimente, cu datele pe care acestea le furnizează. Spuneți, de exemplu, introducerea utilizatorului pe care o proiectați apoi într-una sau mai multe componente. Acest lucru duce la o mulțime de push-and-pull în cod pentru a menține totul în sincronizare.

acest lucru este în cazul în care modelul de proiectare observator poate ajuta — permite unu-la-mai multe date de legare între elemente. Această legare de date unidirecțională poate fi condusă de evenimente. Cu acest model, puteți construi Cod reutilizabil care rezolvă nevoile dvs. specifice.

în acest articol, aș dori să exploreze modelul de proiectare observator. Vă va ajuta să rezolvați o problemă comună pe care o vedeți în scripturile din partea clientului. Aceasta este legarea datelor unu-la-mulți, unidirecțională și bazată pe evenimente. Este o problemă care apare adesea atunci când aveți multe elemente care trebuie să fie sincronizate.

voi folosi ECMAScript 6 pentru a ilustra modelul. Da, vor exista clase, funcții săgeată și constante. Simțiți-vă liber să explorați aceste subiecte pe cont propriu dacă nu sunteți deja familiarizați. Voi folosi părți din ES6 care introduc numai zahăr sintactic, deci este portabil cu ES5 dacă este necesar.

și voi folosi Test-Driven-Development (TDD) pentru a lucra la model. În acest fel aveți o modalitate de a ști cum este utilă fiecare componentă.

noile caracteristici lingvistice din ES6 creează un cod succint. Deci, să începem.

Observatorul evenimentului

o vizualizare la nivel înalt a modelului arată astfel:

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

după ce am concretiza modelul observator voi adăuga un număr de cuvinte pe care îl folosește. Componenta word count va lua acest observator și va aduce totul împreună.

pentru a inițializa EventObserver face:

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

începeți cu o listă goală de evenimente observate și faceți acest lucru pentru fiecare nouă instanță. De acum înainte, să adăugăm mai multe metode în interiorul EventObserver pentru a concretiza modelul de proiectare.

metoda Abonare

pentru a adăuga noi evenimente face:

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

apuca lista de evenimente observate și împinge un element nou la matrice. Lista de evenimente este o listă de funcții de apel invers.

o modalitate de a testa această metodă în JavaScript simplu este după cum urmează:

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

eu folosesc aserțiuni nod pentru a testa această componentă în nod. Exact aceleași afirmații există ca și afirmațiile Chai.

notă lista evenimentelor observate constă în apeluri umile. Apoi verificăm lungimea listei și afirmăm că apelul invers este pe listă.

metoda de dezabonare

pentru a elimina evenimentele fac:

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

filtrați din listă orice se potrivește cu funcția de apel invers. Dacă nu există nici o potrivire, callback ajunge să rămână pe listă. Filtrul returnează o nouă listă și reatribuie lista observatorilor.

pentru a testa această metodă frumoasă, faceți:

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

apelul invers trebuie să corespundă aceleiași funcții din listă. Dacă există o potrivire, metoda de dezabonare o elimină din listă. Notă testul utilizează funcția de referință pentru a adăuga și elimina.

metoda de difuzare

pentru a apela toate evenimentele fac:

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

aceasta iterează prin lista evenimentelor observate și execută toate callback-urile. Cu aceasta, veți obține relația necesară unu-la-mulți cu evenimentele abonate. Treceți în parametrul data care face ca datele de apel invers să fie legate.

ES6 face Codul mai eficient cu o funcție săgeată. Rețineți funcția (subscriber) => subscriber(data) care face cea mai mare parte a lucrării. Această funcție săgeată cu o singură linie beneficiază de această sintaxă ES6 scurtă. Aceasta este o îmbunătățire clară în limbajul de programare JavaScript.

pentru a testa această metodă de difuzare, faceți:

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

utilizați let în loc de const pentru a putea schimba valoarea variabilei. Acest lucru face ca variabila să fie mutabilă, ceea ce îmi permite să-i realoc valoarea în interiorul apelului invers. Folosind un let în codul dvs. trimite un semnal colegilor programatori că variabila se schimbă la un moment dat. Acest lucru adaugă lizibilitate și claritate codului dvs.

acest test îmi dă încrederea necesară pentru a mă asigura că observatorul lucrează așa cum mă aștept. Cu TDD, este vorba despre construirea codului reutilizabil în JavaScript simplu. Există beneficii pentru scrierea codului testabil în JavaScript simplu. Testați totul și păstrați ceea ce este bun pentru reutilizarea codului.

cu aceasta, am concretizat EventObserver. Întrebarea este, ce poți construi cu asta?

The Observer Pattern in Action: A blog Word Count Demo

pentru demo, timp pentru a pune în aplicare o postare pe blog în cazul în care se păstrează numărul de cuvinte pentru tine. Fiecare apăsare de tastă pe care o introduceți ca intrare va fi sincronizată de modelul de proiectare a Observatorului. Gândiți-vă la aceasta ca la o introducere liberă a textului în care fiecare eveniment declanșează o actualizare a locului în care aveți nevoie să mergeți.

pentru a obține un număr de cuvinte din introducerea liberă a textului, se poate face:

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

gata! Se întâmplă multe în această funcție pură aparent simplă, deci ce zici de un test de unitate umil? În acest fel este clar ce am intenționat să fac:

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

notați șirul de intrare oarecum ciudat din interiorul blogPost. Intenționez ca această funcție să acopere cât mai multe cazuri de margine. Atâta timp cât îmi dă un număr adecvat de cuvinte, ne îndreptăm, de fapt, în direcția cea bună.

ca o notă laterală, aceasta este puterea reală a TDD. Se poate repeta această implementare și se pot acoperi cât mai multe cazuri de utilizare. Testul unitar vă spune cum mă aștept să se comporte acest lucru. Dacă comportamentul are un defect, din orice motiv, este ușor să îl iterați și să îl modificați. Cu testul, există suficiente dovezi lăsate în urmă pentru ca orice altă persoană să facă schimbări.

este timpul să conectați aceste componente reutilizabile la DOM. Aceasta este partea în care ajungeți să folosiți JavaScript simplu și să-l sudați chiar în browser.

o modalitate de a face acest lucru ar fi să aveți următorul HTML pe pagină:

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

urmat de acest 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));

luați tot codul reutilizabil și puneți la punct modelul de proiectare a Observatorului. Aceasta va urmări modificările din zona de text și vă va oferi un număr de cuvinte chiar sub ea. Folosesc body.appendChild() în API-ul DOM pentru a adăuga acest element nou. Apoi, atașarea ascultătorii eveniment să-l aducă la viață.

notă cu funcțiile săgeată este posibilă conectarea evenimentelor cu o singură linie. De fapt, difuzați modificări bazate pe evenimente tuturor abonaților cu acest lucru. () => blogObserver.broadcast() face cea mai mare parte a muncii aici. Se trece chiar și în cele mai recente modificări în zona de text chiar în funcția de apel invers. Da, scripting-ul din partea clientului este super cool.

nici un demo este completă fără o puteți atinge și tweak, mai jos este CodePen:

a se vedea Pen-ul Modelul Observator de SitePoint (@SitePoint) pe CodePen.

acum, nu aș numi această caracteristică completă. Este doar un punct de plecare al modelului de proiectare a Observatorului. Întrebarea în mintea mea este, cât de departe ești dispus să mergi?

Privind înainte

depinde de tine să duci această idee și mai departe. Există multe moduri în care puteți utiliza modelul de proiectare a Observatorului pentru a construi noi funcții.

puteți îmbunătăți demo cu:

  • o altă componentă care numără numărul de paragrafe
  • o altă componentă care arată o previzualizare a textului introdus
  • îmbunătățiți previzualizarea cu suport markdown, de exemplu

acestea sunt doar câteva idei pe care le puteți face pentru a vă scufunda mai adânc în acest sens. Îmbunătățirile de mai sus vă vor provoca Cotletele de programare.

concluzie

modelul de proiectare observator vă poate ajuta să rezolvați problemele din lumea reală în JavaScript. Acest lucru rezolvă problema perenă de a păstra o grămadă de elemente sincronizate cu aceleași date. Așa cum se întâmplă adesea, când browserul declanșează evenimente specifice. Sunt sigur că majoritatea dintre voi ați întâlnit până acum o astfel de problemă și ați alergat spre Instrumente și dependențe terțe.

acest model de design vă echipează pentru a merge în măsura în care imaginația ta este dispus să meargă. În programare, abstractizați soluția într-un model și construiți Cod reutilizabil. Nu există nici o limită la cât de departe vă va duce acest lucru.

sper să vedeți cât de mult, cu puțină disciplină și efort, puteți face în JavaScript simplu. Noile caracteristici din limbă, cum ar fi ES6, vă ajută să scrieți un cod succint care este reutilizabil.

acest articol a fost evaluat de către Giulio Mainardi. Vă mulțumim tuturor recenzorilor SitePoint pentru a face conținutul SitePoint cel mai bun!

Lasă un răspuns

Adresa ta de email nu va fi publicată.