Karcsúsítsa a modelleket és a vezérlőket aggodalmakkal, szolgáltatási objektumokkal és asztali modellekkel
Feladva 2015. augusztus 24-én
Az egységes felelősség elve
Egy osztálynak csak egy oka lehet a változtatásra. ? - Bob bácsi
Az egyetlen felelősség elve azt állítja, hogy minden osztálynak pontosan egy felelősséggel kell rendelkeznie. Más szóval, minden osztálynak aggódnia kell a funkcionalitás egyetlen egyedi rögjéért, legyen az User, Post vagy InvitesController. Az ezen osztályok által példányosított objektumoknak a felelősségükkel kapcsolatos üzenetek küldésével és megválaszolásával kell foglalkozniuk, semmi mással.
Ez egy általános Rails mantra, amelyet sok oktatóanyag, és így sok kezdő követ, amikor elkészíti következő alkalmazását. Míg a zsírmodellek valamivel jobbak, mint a zsírkontrollerek, mégis ugyanazok az alapvető problémák szenvednek: amikor az objektum számos felelőssége megváltozik, magának az objektumnak is meg kell változnia, aminek eredményeként ezek a változások az egész alkalmazásban elterjednek. Hirtelen egy modell apró módosítása megtörte a tesztek felét!
Az egyetlen felelősség elvének betartása előnyei közé tartozik (de nem kizárólag):
- DRYer-kód: amikor a funkcionalitás minden egyes bitjét beillesztettük a saját objektumába, akkor sokkal kevesebbet ismételgetünk a kódban.
- A változás könnyű: az összetartó, lazán összekapcsolt tárgyak magukban foglalják a változást, mivel nem tudnak mást és nem érdekelnek semmi mást. A felhasználó módosítása egyáltalán nem érinti a Postot, mivel a Post még azt sem tudja, hogy létezik Felhasználó.
- Összpontosított egységtesztek: A függőségek sodródó hálózatának összehangolása helyett, csak a tesztek beállítása érdekében, az egyetlen felelősséggel rendelkező objektumok egyszerűen egységesen tesztelhetők, kihasználva a duplákat, gúnyokat és csípéseket, hogy megakadályozzák a tesztek majdnem olyan gyakran megtörését.
Egyetlen objektum sem lehet mindenható, beleértve a modelleket és a vezérlőket is. Az, hogy a vanilla Rails 4 alkalmazáskönyvtár modelleket, nézeteket, vezérlőket és segédprogramokat tartalmaz, nem jelenti azt, hogy Ön csak erre a négy tartományra korlátozódik.
Tucatnyi tervezési minta létezik az egyetlen felelősség elvének kezelésére a Rails-ben. Beszélni fogok azokról a néhányról, amelyeket felfedeztem ezen a nyáron.
A modellszerepek aggályokkal való összefoglalása
Képzelje el, hogy a Reddithez vagy a Hacker Newshez hasonló egyszerű online webhelyet épít. A felhasználó és az alkalmazás közötti fő interakció a bejegyzések benyújtása és szavazása.
Most képzelje el, hogy azt szeretné, ha a felhasználók szavazhatnak mind a bejegyzésekről, mind a megjegyzésekről. Úgy döntött, hogy megvalósít egy alapvető polimorf asszociációt, és ezzel végül:
UH Oh. Már van néhány duplikált kód a #vote-tal! . A helyzetet még rosszabbá akarja tenni, hogy mind a fel-, mind a visszhangokat megkapja.
A Vote API-ja megváltozott, mivel a .new és a .create most már megkövetel egy típusú argumentumot. Csak a hozzászólások és megjegyzések kis esetében ez nem túl nagy változás. De mi történik, ha van 10 modellje, amelyre szavazni lehet? 100?
Az aggodalmak lényegében olyan modulok, amelyek lehetővé teszik a modell szerepek külön fájlokba foglalását a SZÁMÍTÁS érdekében. Példánkban a Post és a Comment egyaránt betöltheti a szavazható szerepét, így magukban foglalják a Votable aggodalmát is, hogy hozzáférjenek ehhez a közös viselkedéshez. Az aggodalom nagyszerű a modelljei által játszott különböző szerepek megszervezésében. Az aggodalmak azonban nem jelentenek megoldást egy túl sok felelősséggel rendelkező modellre.
Az alábbiakban egy olyan aggodalomra mutatunk be példát, amely még mindig megsérti az egyetlen felelősség elvét.
Ez a probléma nem valami jó megoldás az aggodalmakra. A felhasználói modell nem tudhat a UserMailerről. Míg a tényleges user.rb fájl nem tartalmaz hivatkozást a UserMailerre, a User osztály igen.
Az aggodalmak remek eszköz a viselkedés megosztásához a modellek között, de ezeket felelősen és egyértelmű szándékkal kell felhasználni.
A vezérlő összetettségének csökkentése a Service objektumokkal
Az e-mailek témájában vessünk egy pillantást a vezérlőkre. Képzelje el, hogy azt szeretnénk, ha a felhasználók az e-mailek listájának elküldésével meghívhatnák barátaikat. Amikor meghívást kap egy e-mailre, egy új Meghívó objektum jön létre, hogy nyomon kövesse, kiket hívtak meg már. Az érvénytelen e-maileket a Flash egy hibaüzenettel jeleníti meg.
Mi a baj pontosan ezzel a kóddal, amelyet megkérdezhet? A vezérlő egyetlen felelőssége a HTTP kérések elfogadása és az adatokkal történő válaszadás. A fenti kódban meghívó küldése az e-mailek listájára példa az üzleti logikára, amely nem tartozik a vezérlőbe. A meghívók küldése egység teszteléssel lehetetlen, mivel ez a szolgáltatás annyira szorosan kapcsolódik az InvitesControllerhez. Megfontolhatja ezt a logikát az Invite modellbe, de ez nem sokkal jobb. Mi történne, ha hasonló viselkedést szeretne az alkalmazás egy másik részében, amely nem kapcsolódik egyetlen modellhez vagy vezérlőhöz sem?
Szerencsére van megoldás! Sokszor egy speciális üzleti logika, például az ömlesztett e-mail küldés, beágyazható egy sima régi rubinobjektumba (szeretettel PORO néven). Ezek az objektumok, amelyeket gyakran Service vagy Interaction objektumoknak neveznek, elfogadják a bevitelt, elvégzik a munkát és visszaadják az eredményt. A különböző modellek több rekordjának létrehozásával és megsemmisítésével járó összetett interakciók esetén a szolgáltatási objektumok nagyszerű módja annak, hogy ezt a felelősséget a Rails a Rails által biztosított modellekből, vezérlőkből, nézetekből és segítők keretrendszeréből fedezze.
Ebben a példában az e-mailek tömeges küldésének felelőssége áthelyeződött a vezérlőből a BulkInviter nevű szolgáltatásobjektumba. Az InvitesController nem tudja, vagy nem érdekli, hogy a BulkInviter ezt pontosan hogyan teljesíti; csak annyit tesz, hogy felkéri a BulkInvitert, hogy végezze el munkáját. Bár sokkal jobb, mint a zsírszabályozó változata, még van hová fejlődni. Figyelje meg, hogyan kell az InvitesControllernek még mindig tudnia, hogy a BulkInviter rendelkezik érvénytelen e-mailek listájával? Ez a további függőség tovább párosítja az InvitesControllert a BulkInviterhez .
Az egyik megoldás az, ha a szolgáltatásobjektumok összes kimenetét egy Response objektumba csomagolja.
Most az InvitesController valóban tudatlan a BulkInviter működéséről; mindössze annyit tesz, hogy megkéri a BulkInvitert, hogy végezzen valamilyen munkát, és elküldi a választ a nézetbe.
A szolgáltatásobjektumok egyszerű tesztelésre képesek, könnyen cserélhetők, és az alkalmazás növekedésével újból felhasználhatók. Ugyanakkor, mint bármelyik tervezési minta, a szolgáltatási objektumokhoz kapcsolódó költségek is tartoznak. A szolgáltatási objektum tervezési mintázatának visszaélése gyakran szorosan összekapcsolt objektumokat eredményez, amelyek inkább a módszerek megváltoztatásának és kevésbé az egyetlen felelősség elvének a követését érzik. A több objektum bonyolultabbá is válik, és egy adott szolgáltatás pontos helyének megtalálása magában foglalja a szolgáltatás-könyvtár ásását.
A legnagyobb kihívás, amellyel a szolgáltatási objektumok tervezésénél szembesültem, egy intuitív API meghatározása, amely könnyen kommunikálja az objektum felelősségét. Az egyik megközelítés az, hogy ezeket az objektumokat úgy kezeljük, mint a procokat vagy a lambdasokat, a #call vagy #perform metódus végrehajtásával, amely munkát végez. Bár ez kiválóan alkalmas az interfész szabványosítására a szolgáltatási objektumok között, nagyban támaszkodik a leíró osztálynevekre az objektum felelősségének közléséhez.
Az egyik ötlet, amelyet a szolgáltatási objektumok további kommunikációjára használtam, az, hogy elnevezem őket a saját tartományukba:
Ezeknek a szolgáltatásobjektumoknak a pontos megvalósítása nagyrészt stílusalapú, és az üzleti logika összetettségétől függ.
Az Active Record Model előnyeinek kihasználása
Az utolsó téma, amelyet le akarok térni, a táblázatlan modellek ötlete. A Rails 4-től kezdve felveheti az ActiveModel: Model modult, amely lehetővé teszi, hogy egy objektum interakcióba lépjen az Action Pack-szel, és megszerezhesse az Active Record modellek által élvezett teljes felületet. Az ActiveModel: Modellt tartalmazó objektumok nem maradnak fenn az adatbázisban, de attribútum-hozzárendeléssel példányosíthatók, beépített ellenőrzésekkel validálhatók, és űrlapokat segítenek űrlapokkal segíteni, és még sok más!
Mikor készülne asztal nélküli modell? Nézzünk meg egy példát!
Képzelje el, hogy online jelszóerősség-ellenőrzőt építünk. A jó jelszónak számos jellemzővel kell rendelkeznie, például 8 karakteres minimum, valamint nagy- és kisbetűk kombinációja. Mivel ezeket a jelszavakat alkalmazásunk másutt nem használják, nem akarjuk megőrizni őket az adatbázisban.
Első kísérletünk valamilyen szolgáltatási objektumot tartalmazhat.
Amíg ez működik, valami nem érzi az új PasswordChecker szolgáltatási objektumunkat. Nincs interakció egyetlen modellel sem, és nem változtat semmilyen állapotot. A szolgáltatásobjektum API kényelmetlen, mivel nem világos, hogy a #perform lekérdezés vagy parancs. Ha visszalépünk és átgondoljuk, hogy mi is pontosan ennek a szolgáltatási objektumnak a felelőssége, hamarosan megérkezünk a jelszó erősségének érvényesítésére. Más szavakkal, a PasswordChecker tartalmaz és érvényesít egy adatsort, hasonlóan az Active Record modellekhez.
Ez nagyszerű eset az asztal nélküli modelleknél!
Nemcsak a beépített ellenőrzések erejét élvezzük, hanem sokkal könnyebbé válik a hibaüzenetek renderelése és az új jelszó beküldéséhez szükséges űrlap létrehozása.
Az aggodalmak, a szolgáltatási tárgyak és az asztal nélküli modellek mind kiváló módszerek a Rails alkalmazás felépítésekor tapasztalt növekvő fájdalmak leküzdésére. Fontos, hogy ne erőltesse a tervezési mintákat, hanem fedezze fel azokat az alkalmazás építése során. Sok esetben nagyon sok értelme van a modellszerepek SZÁRÍTÁSA aggodalmakkal, szolgáltatási objektumréteg létrehozása a modellek és a vezérlők között, vagy az ideiglenes adatok táblázatlan modellekbe történő beágyazása. Máskor nagyon korai optimalizálási szaga van, és nem a legjobb megközelítés.
Mint minden programozásnál, a tanulás legjobb módja az, ha bepiszkítja a kezét!
- Karcsúsítja Docker képeit
- Karcsúsítja Hugo statikus webhelyét, Allison Letson
- A karcsúsítás hatással lehet a D-vitamin szintjére24
- Karcsúsítsa le a lábát egy combemeléssel - reneszánsz a plasztikai sebészetben
- Új tanulmány a fogyásról, a TCM út; Fedezze fel az integratív orvoslást