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:
- Kezelő — Meghatározza azt a felületet, ahol a kéréseket kezelik. Kezeli a láncban összekapcsolt kéréseket is.
- Ü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
- 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.
- 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.
- 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 next
callback-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!