Futtasson funkciók láncolatát, amelyek elvégzik a dolgokat

A tervezési minták ismerete létfontosságú a szoftveriparban, mivel bizonyítottan megoldják az üzleti alkalmazások valós problémáit. Például a Közzététel/Feliratkozás egy gyakori minta, amelyet széles körben használnak a DOM-ban. A Command mintát a Redux-ban használják, amely rövid időn belül felvirágzott, egyedülálló, robusztus és egyszerű alkalmazásállapot-kezelési képessége miatt, amely szintén nagyon skálázható.

A formatervezési minták érdekessége, hogy nem mindenki számára egyforma megoldások. Egyes tervezési minták különböző helyzetekben hatékonyabban működhetnek, mint mások, és a fejlesztőn múlik, hogy mikor és hogyan használja őket a leghatékonyabban az alkalmazásaiban.

Ebben a cikkben a felelősségi lánc tervezési mintáját fogjuk áttekinteni azáltal, hogy megvalósítunk egyet, és bemutatunk néhány használati esetet.

A felelősségi lánc (COR) egy olyan minta, amely lehetővé teszi bizonyos kérések több objektum általi küldését, fogadását és kezelését. Ezek az objektumok (amelyek csak függvények) nem függenek az előző vagy a következő kérés megvalósítási részleteitől, és a végrehajtás során eldönthetik, hogy mit tegyenek. Néhány hasznos, intuitív képességet biztosítanak. Ilyen képességek közé tartozik a lánc megszakítása vagy folytatása, a köztesszoftver-folyamat felépítése és így tovább.

Íme egy példa a DOM-ban használt mintára:

Amikor rákattint a gombra, a gombhoz csatlakoztatott figyelő meghívódik. Amikor a függvény véget ér, a „kérés” átadásra kerül (vagy buborékolva) a szülőjének:

A e.stopPropagation() hívásával dönthet úgy, hogy leállítja ezt a folytatást (vagy buborékolást) a szülőnek:

Ennek a mintának nem igazán van „hivatalos” vagy helyes módja. Amíg a funkciók irányíthatóan és kiszámíthatóan egymás után láncolhatnak, addig jó formában vagy. Általában azonban két fő szerep határozza meg:

  1. Kezelő — Meghatározza azt a felületet, ahol a kéréseket kezelik. Kezeli a láncban összekapcsolt kéréseket is.
  2. Ügyfél – kezdeményezi a kérést a láncban lévő kezelőhöz.

Íme a minta egy variációja, amely a „lényegből” származik:

A lánc akkor következik be, amikor a add függvény this-t ad vissza:

Ez azt jelenti, hogy annyiszor hívható újra, amennyit csak akarunk, mivel a példány a hívás végén ismét visszakerül:

A lánc megszakításának vagy folytatásának felelőssége minden add funkcióblokkot visel. Példánkban van egy add metódus, amely egyféleképpen összegzi az értékét:

Ami a add metóduson belül történik, az szó szerint bármi lehet, és nem kell semmitől függnie, ami kívül esik a funkció hatókörén. Például ki tudjuk használni ezt az API kérések láncolatával, ahol a lánc minden egyes kérése a saját logikájával új összeget tud kiszámolni, és az előző összeg eredményét átadja a lánc következő, működésében érdekelt függvényének. ezzel.

Tegyük fel, hogy olyan helyzetben vagyunk, amikor képzeletbeli raktárunkból adunk el háziállatokat. Összesítenünk kell a raktárunkban akciós háziállatokat, hogy megállapíthassuk, szükség van-e a szokásosnál korábban újratelepíteni őket egy országos sürgősségi otthontartási elrendelés miatt. Tesszük ezt, mert arra számítunk, hogy a következő néhány hónapban az olyan gyakori háziállatok, mint a kutyák és macskák eladása virágzik:

A kibővített CumulativeSum ugyanazt a célt éri el, de most lehetővé teszi számunkra, hogy testreszabjuk a hogyan viselkedését a következő összeg meghatározásához.

Az alábbiakban van egy PetSum osztályunk, amely tartalmaz egy összeget. Megvan a saját add metódusa, amely bármely CumulativeSum-et kezdeményez a add metódusának meghívásával (ez meghívja az összes utána linkelt kérésláncot). Ha emlékszel a cikk elején, a „kezelő” kifejezés az alábbi PetSum:

És itt van egy példa, ahol négy CumulativeSums jön létre és kapcsolódnak egymáshoz, és mindegyik más állatfajt képvisel, mivel raktárunkban több faj található:

Mindegyiknek megvan a maga módja a fajai összegének kiszámítására, vagy akár úgy is dönthet, hogy egyáltalán nem tesz semmit:

A végösszeg megszerzéséhez mindössze annyit kell tennie, hogy meghívja a add metódust az egyik példányon:

Látod milyen könnyű volt?

Elindíthatjuk a kérésláncot a köztes példányok egyikéből. Például kezdhetjük a kutyákkal, és megfeledkezhetünk a macskákról (ne felejtsük el, hogy a catsStorage volt az első kérés, de kezdhetjük a dogsStorage-tal, és onnan folytathatjuk a kérések láncolatát):

Ez akkor hasznos, ha valamilyen váltást szeretnénk végrehajtani, hogy az egyiket vagy a másikat bármikor kikapcsolhassuk, például amikor egy ügyfél időpontot egyeztetett az összes mókusunk megvásárlására egy adott napon (pl. március 23-án 13-14 óra között):

Ha ismeri a „Linked List” adatstruktúrát, rájöhet, hogy ezek meglepően hasonlóak. És ők! Példánkban minden művelet, amelyet egy linkelt listával végezhet, elvégezhető. A lánc minden egyes funkcióját bejárhatjuk – így visszafelé is – úgy, hogy mindegyikhez csatolunk egy prev (korábbi) tulajdonságot is:

Az eredmény:

Valós forgatókönyvek

  1. Kávéfőző — A kávéfőző programozható a COR mintával, ahol a láncban minden egyes kérés/kezelő meghatároz egy külön hozzávalót, amelyet hozzáadhat a géphez. A folyamat szorosan követi, hogyan készítünk már ma kávét, ahol bármikor abbahagyhatjuk a hozzávalókat, vagy választhatjuk, hogy folytassuk az eszpresszóval, tejjel, mandulamorzsával stb.
  2. ATM automata – Ha azt a lehetőséget választja, hogy 100 dollárt vegyen fel 20 dolláros bankjegyekben, a gép öt 20 dolláros bankjegyet ad ki, amíg el nem éri a kért összeget. Ekkor ér véget a művelet.
  3. Transzformátorok — Transzformátorok/elemzők láncának felhasználása valamilyen egyedi AST-ben (szó szerint csak erre gondoltam, amikor ezt a cikket írtam, szóval ez nem egy teljes harcban tesztelt vagy optimalizált kód, de lefuttattam a kódot és működik szépen):

Az eredmény:

Minden transzformátorfüggvényünkben a nextcallback-et hívjuk, amely egy olyan függvény, amelyet a lánc következő függvényének meghívására hoztunk létre.

Dönthetünk úgy, hogy nem folytatjuk a láncot, amikor csak akarjuk a függvényen belül. Például megállhatunk a handleAlign függvény meghívása előtt, ha a textAlign nem objektum (az objektum érvénytelen lenne a DOM elemben):

Következtetés

És ezzel a cikk véget is ért! Remélem ezt értékesnek találtad. A jövőben még többre figyelj!