JavaScript Design Patterns: The Observer Pattern

Javascriptissä on ongelma, joka tulee esiin usein. Tarvitset tavan päivittää sivun osia vastauksena tiettyihin tapahtumiin näiden tarjoamilla tiedoilla. Sano esimerkiksi käyttäjän tulo, jonka sitten projisoit yhteen tai useampaan komponenttiin. Tämä johtaa paljon push-and-pull koodi pitää kaiken synkronoituna.

tässä havaitsijan suunnittelukuvio voi auttaa-se mahdollistaa yhdestä moneen tiedon sitomisen elementtien välillä. Tämä yksisuuntainen tietojen sitominen voi olla tapahtumavetoista. Tämän kuvion, voit rakentaa uudelleenkäytettäviä koodi, joka ratkaisee erityistarpeisiin.

tässä artikkelissa haluaisin tutustua Observerin suunnittelukuvioon. Se auttaa sinua ratkaisemaan yhteisen ongelman näet client-side scripting. Se on yksi-moneen, yksisuuntaista ja tapahtumavetoista tietojen sitomista. Se on ongelma, joka tulee esiin usein, kun sinulla on monia elementtejä, jotka on synkronoitu.

käytän ECMAScript 6: ta kuvaamiseen. Kyllä, tulee olemaan luokkia, nuolitoimintoja ja vakioita. Voit vapaasti tutkia näitä aiheita itse, jos et ole jo tuttu. Käytän ES6: n osia, jotka esittelevät vain syntaktista sokeria, joten se on tarvittaessa kannettava ES5: llä.

ja käytän Test-Driven-Development (TDD) kaavan työstämiseen. Näin sinulla on tapa tietää, miten kukin komponentti on hyödyllinen.

ES6: n uudet kieliominaisuudet tekevät jonkinlaisesta ytimekkäästä koodista. Aloitetaan.

Tapahtumatarkkailija

korkean tason näkemys kuviosta näyttää tältä:

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

kun olen täsmentänyt tarkkailijakuviota, lisään sanaluvun, joka käyttää sitä. Sanalukukomponentti vie tämän tarkkailijan ja kokoaa kaiken yhteen.

alustaa EventObserver do:

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

Aloita tyhjästä luettelosta havaituista tapahtumista ja tee tämä jokaiselle uudelle tapaukselle. Tästä eteenpäin lisätään lisää menetelmiä EventObserver: n sisälle, jotta muotoilukuviota voidaan täsmentää.

merkintätapa

uusien tapahtumien lisääminen ei:

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

nappaa lista havaituista tapahtumista ja työnnä uusi kohde array. Luettelo tapahtumista on luettelo takaisinsoittotoiminnoista.

yksi tapa testata tätä menetelmää plain Javascriptissä on seuraava:

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

käytän Solmuväitteitä Testatakseni tätä komponenttia solmussa. Täsmälleen samat väitteet ovat olemassa kuin Chai väitteet liian.

huomaa, että havaittujen tapahtumien luettelo koostuu nöyristä takaisinkutsuista. Sitten tarkistamme listan pituuden ja vakuutamme, että takaisinsoitto on listalla.

Peruutusmenetelmä

tapahtumien poistaminen ei:

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

suodata luettelosta se, mikä vastaa takaisinsoittotoimintoa. Jos vastaavuutta ei löydy, soittaja saa jäädä listalle. Suodatin palauttaa uuden listan ja jakaa tarkkailijoiden luettelon uudelleen.

testataksesi tätä mukavaa menetelmää, tee:

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

takaisinkutsun täytyy vastata samaa toimintoa, joka on listalla. Jos löytyy vastaavuus, unsubscribe-menetelmä poistaa sen luettelosta. Huomaa, että testi käyttää funktion viittausta sen lisäämiseen ja poistamiseen.

lähetystapa

soittaa kaikkiin tapahtumiin do:

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

tämä iteroi läpi luettelon havaituista tapahtumista ja suorittaa kaikki takaisinkutsutiedot. Tämän, saat tarvittavat yksi-to-monet suhde tilatut tapahtumat. Ohitat parametrin data, joka tekee takaisinsoittotiedoista sidottuja.

ES6 tehostaa koodia nuolitoiminnolla. Huomaa (subscriber) => subscriber(data) funktio, joka tekee suurimman osan työstä. Tämä one-liner arrow-toiminto hyötyy tästä lyhyestä ES6-syntaksista. Tämä on selvä parannus JavaScript – ohjelmointikieleen.

tämän lähetysmenetelmän testaamiseksi do:

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

käytä let sijasta const, jotta voimme muuttaa muuttujan arvoa. Tämä tekee muuttujan muunneltavaksi, mikä mahdollistaa sen arvon uudelleensijoittamisen takaisinkutsun sisällä. Käyttämällä koodia let viestittää muille ohjelmoijille, että muuttuja muuttuu jossain vaiheessa. Tämä lisää luettavuutta ja selkeyttä JavaScript-koodin.

tämä testi antaa minulle tarvittavan luottamuksen, jotta tarkkailija toimii odotetusti. Kanssa TDD, se on kyse rakentaa uudelleenkäytettäviä koodia plain JavaScript. On etuja kirjallisesti testattavan koodin plain JavaScript. Testaa kaikki ja säilytä, mikä on hyvä koodin uudelleenkäyttöön.

tällä olemme täsmentäneet EventObserver. Kysymys kuuluu, mitä tällä voi rakentaa?

The Observer Pattern in Action: a Blog Word Count Demo

for the demo, time to put in a blog post where it keep the word count for you. Jokainen näppäilyn syötät input saa synkronoitu tarkkailija suunnittelu kuvio. Ajattele sitä ilmaisena tekstisyötteenä, jossa jokainen tapahtuma ampuu päivityksen sinne, minne sitä tarvitaan.

saada sanamäärä vapaa tekstinsyöttö, yksi voi tehdä:

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

sovittu! Tässä näennäisesti yksinkertaisessa puhtaassa funktiossa tapahtuu paljon, joten miten olisi vaatimaton yksikkötesti? Näin on selvää, mitä aioin tehdä.:

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

huomaa, että blogPostsisällä on hieman omituinen tulonaru. Tarkoitukseni on, että tämä tehtävä kattaa mahdollisimman monta edge-tapausta. Niin kauan kuin se antaa minulle oikean sanaluvun, olemme itse asiassa menossa oikeaan suuntaan.

Sivuhuomautuksena tämä on TDD: n todellinen voima. Voidaan iteroida tätä täytäntöönpanoa ja kattaa niin monta käyttötapausta kuin mahdollista. Yksikkötesti kertoo, miten odotan tämän käyttäytyvän. Jos käyttäytymisessä on jostain syystä virhe, sitä on helppo iteroida ja nipistää. Testin myötä jäljelle jää riittävästi todisteita, jotta kuka tahansa muu ihminen voisi tehdä muutoksia.

aika kytkeä nämä uudelleenkäytettävät komponentit DOM: iin. Tämä on osa, jossa saat käyttää plain JavaScript ja hitsata sen suoraan selaimeen.

tapa tehdä se olisi, että sivulla olisi seuraava HTML:

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

seuraa tätä JavaScriptiä:

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));

Ota kaikki uudelleenkäytettävä koodi ja ottaa käyttöön observer suunnittelu kuvio. Tämä seuraa muutoksia tekstialueella ja antaa sinulle sanamäärän aivan sen alapuolella. Käytän body.appendChild(): ää DOM API: ssa lisätäkseni tämän uuden elementin. Sitten kiinnität tapahtuman kuuntelijat herättämään sen eloon.

nuotin Nuolifunktioilla on mahdollista langoittaa yksiviivaisia tapahtumia. Itse asiassa, lähetät tapahtumavetoisia muutoksia kaikille tilaajille tällä. () => blogObserver.broadcast() tekee suurimman osan työstä täällä. Se jopa siirtää viimeisimmät muutokset tekstialueelle suoraan takaisinsoittotoimintoon. Kyllä, asiakaspuolen käsikirjoittaminen on supersiistiä.

no demo is complete without one you can touch and tweak, alla on CodePen:

See the Pen the Observer Pattern by Sitepoint (@SitePoint) on CodePen.

nyt en kutsuisi tätä ominaisuutta täydelliseksi. Se on vain observer-suunnittelukaavan lähtökohta. Kysymys kuuluu: kuinka pitkälle olet valmis menemään?

Katse eteenpäin

on sinun asiasi viedä tätä ajatusta vielä pidemmälle. On monia tapoja, joilla voit käyttää observer suunnittelukuvio rakentaa uusia ominaisuuksia.

demoa voi parantaa:

  • toinen komponentti, joka laskee kappaleiden määrän
  • toinen komponentti, joka näyttää syötetyn tekstin esikatselun
  • Paranna esikatselua markdown-tuella, esimerkiksi

nämä ovat vain muutamia ideoita, joilla voit uppoutua syvemmälle tähän. Parannukset edellä haastaa ohjelmointi kyljykset.

Conclusion

observer-suunnittelukuvio voi auttaa ratkaisemaan reaalimaailman ongelmia Javascriptissä. Tämä ratkaisee monivuotisen ongelman pitää joukko elementtejä synkronoitu samat tiedot. Kuten usein, kun selain ampuu tiettyjä tapahtumia. Olen varma, että useimmat teistä ovat tähän mennessä törmänneet tällaiseen ongelmaan ja ovat ajaneet kohti työkaluja ja kolmannen osapuolen riippuvuuksia.

tämä kaava antaa sinulle mahdollisuuden mennä niin pitkälle kuin mielikuvituksesi on valmis menemään. Ohjelmoinnissa ratkaisu abstrahoidaan kuvioksi ja rakennetaan uudelleenkäytettävää koodia. Ei ole mitään rajaa, kuinka pitkälle tämä vie sinut.

toivottavasti Huomaatte, kuinka paljon pienellä kurinalaisuudella ja vaivannäöllä voi tehdä pelkällä Javascriptillä. Kielen uudet ominaisuudet, kuten ES6, auttavat kirjoittamaan ytimekästä koodia, joka on uudelleenkäytettävä.

tämän artikkelin on vertaisarvioinut Giulio Mainardi. Kiitos kaikille sitepointin vertaisarvioijoille siitä, että he ovat tehneet sitepointin sisällöstä parhaan mahdollisen!

Vastaa

Sähköpostiosoitettasi ei julkaista.