Eelmisel nĂ€dalal kirjutasin kuid lubasin rÀÀkida, kuidas seda osaliselt kasulikult kasutada. Selleks pĂŒĂŒan analĂŒĂŒsida, kuidas seda malliosa projektides tavaliselt kasutatakse. Minimaalne vajalik meetodite komplekt repositooriumi jaoks:
<?php
interface PostRepository
{
public function getById($id): Post;
public function save(Post $post);
public function delete($id);
}Siiski, reaalses projektis, kui repositooriumide kasutamine on otsustatud, lisatakse neile sageli meetodeid seadmete valimistamiseks:
<?php
interface PostRepository
{
public function getById($id): Post;
public function save(Post $post);
public function delete($id);
public function getLastPosts();
public function getTopPosts();
public function getUserPosts($userId);
}Neid meetodeid vĂ”iks ellu viia Eloquent'i skoopide kaudu, kuid koormata isendusklasse enda valikukohustustega â ei ole parim idee ning selle kohustuse vĂ€ljatĂ”stmine repositooriumi klassidesse tundub loogiline. Kas see tĂ”esti on nii? Ma jagasin selle liidese visuaalselt kaheks. Esimene osa meetoditest kasutatakse kirjaoperatsioonide jaoks.
Tavalised kirjutamise operatsioonid on:
- uue objekti konstruktsioon ja meetodi ehk PostRepository::save
- PostRepository::getById, tegevus koos olendiga ja pÀrandamine PostRepository::save
- meetodiga PostRepository::delete
Kirjaoperatsioonides ei ole valikumeetodeid kasutuses. Lugemisoperatsioonides aga kasutatakse ainult meetodeid get*. Kui lugeda Interface Segregation Principle (tĂ€ht I ĂŒhes SOLID), siis on selge, et meie liides on liiga suur ja tĂ€idab vĂ€hemalt kahte erinevat kohustust. On aeg jagada see kaheks. Meetod getById on mĂ”lemas vajalik, kuid rakenduste keerukuse kasvades on nende teostused erinevad. Seda nĂ€eme veidi hiljem. Kirjaosa kasutu olemusest kirjutasin eelmisel nĂ€dalal, seega unustan selle siin lihtsalt.
Kuid lugemisosa ei tundu sugugi kasutu, kuna isegi Eloquent'i puhul vÔib siin olla mitu rakendust. Kuidas nimetada klassi? VÔib-olla ReadPostRepository, kuid mustriga Repository on see juba vÀhe seotud. Lihtsalt vÔib nimetada PostQueries:
<?php
interface PostQueries
{
public function getById($id): Post;
public function getLastPosts();
public function getTopPosts();
public function getUserPosts($userId);
}Selle rakendamine Eloquentiga on ĂŒsna lihtne:
limit(/*some limit*/)
->get();
}
/**
* @return Post[] | Collection
*/
public function getTopPosts()
{
return Post::orderBy('rating', 'desc')
->limit(/*some limit*/)
->get();
}
/**
* @param int $userId
* @return Post[] | Collection
*/
public function getUserPosts($userId)
{
return Post::whereUserId($userId)
->orderBy('created_at', 'desc')
->get();
}
}Liidese peab siduma rakendusega, nÀiteks classis AppServiceProvider:
app->bind(PostQueries::class,
EloquentPostQueries::class);
}
}See klass on juba kasulik. See tÀidab oma kohustuse, vabastades kas kontrollereid vÔi olendi klassi. Kontrollers on seda vÔimalik kasutada jÀrgmiselt:
$postQueries->getLastPosts(),
]);
}
} Meetod PostsController::lastPosts lihtsalt kĂŒsib endale mingit rakendust PostsQueries ja töötab selle kallal. Pakkujas sidusime selle klassi PostQueries EloquentPostQueries ja kontrollers tĂ€iendab seda klassi. Kujutame nĂŒĂŒd ette, et meie rakendus on muutunud vĂ€ga populaarseks. Tuhanded kasutajad avavad minutis lehe viimaste postituste jaoks. KĂ”ige populaarsemaid postitusi loetakse samuti vĂ€ga sageli. Andmebaasid ei suuda selliste koormustega vĂ€ga hĂ€sti hakkama saada, seetĂ”ttu kasutatakse standardset lahendust â vahemĂ€lu. Lisaks andmebaasile hoitakse andmete mingit koopia kindlates operatsioonides optimeeritud salvestuses â
Kujutame ette, et meie rakendus on saanud vĂ€ga popiks. Tuhanded kasutajad avavad iga minuti jooksul lehe, kus on viimased postitused. KĂ”ige populaarsemaid postitusi loetakse samuti vĂ€ga tihti. Andmebaasid ei suuda selliste koormustega vĂ€ga hĂ€sti toime tulla, mistĂ”ttu kasutatakse standardlahendust â vahemĂ€lu. Koos andmebaasiga hoitakse teatud operatsioonide jaoks optimeeritud salvestuses ka andmete koopiat â memcached vĂ”i redis.
VahemĂ€lu loogika on tavaliselt ĂŒsna lihtne, kuid selle rakendamine EloquentPostQueries'is ei ole kuigi Ă”ige (vĂ€hemalt Single Responsibility Principle). Tunduvalt loogilisem on kasutada mustrit Dekoraator ja rakendada vahemĂ€lu peamise tegevuse kaudu dekoreerimisega:
base = $base;
$this->cache = $cache;
}
/**
* @return Post[] | Collection
*/
public function getLastPosts()
{
return $this->cache->remember('last_posts',
self::LASTS_DURATION,
function(){
return $this->base->getLastPosts();
});
}
// teised meetodid on praktiliselt samad
}Ărge pöörake tĂ€helepanu liidesele Repository konstruktoris. Arusaamatul pĂ”hjusel otsustati nii nimetada vahemĂ€lule liidese Laravelis.
Klass CachedPostQueries rakendab ainult vahemÀlu. $this->cache->remember kontrollib, kas sellist salvestust ei ole vahemÀlus ning kui ei ole, kutsub tagasi ja salvestab vahemÀlles tagastatud vÀÀrtuse. JÀÀnud on vaid see klass rakendusse integreerida. Me peame veenduma, et kÔik klassid, mis rakenduses nÔuavad liidese rakendamist PostQueries saaksid klassi eksemplari CachedPostQueries. Ent ise CachedPostQueries peab konstruktoris saama parametritena klassi ja kontrollers tÀiendab seda klassi., kuna ta ei saa töötada ilma "pÀris" rakenduseeta. Muudame AppServiceProvider:
app->bind(PostQueries::class,
CachedPostQueries::class);
$this->app->when(CachedPostQueries::class)
->needs(PostQueries::class)
->give(EloquentPostQueries::class);
}
}KĂ”ik minu soovid on ĂŒsna loomulikult iseloomustatud pakkujas. Nii oleme rakendanud vahemĂ€llu salvestamist meie pĂ€ringute jaoks, kirjutades vaid ĂŒhe klassi ja muutes konteineri konfiguratsiooni. ĂlejÀÀnud rakenduse kood ei ole muutunud.
Muidugi, tÀielik vahemÀllu salvestamine nÔuab veel kehtetuks tegemist, et kustutatud artikkel ei jÀÀks veebilehele veel mÔneks ajaks, vaid eemaldataks kohe. Kuid need on juba pisiasjad.
KokkuvĂ”tteks: kasutasime mitte ĂŒhte, vaid lausa kahte mustrit. Muster Command Query Responsibility Segregation (CQRS) pakub tĂ€ielikult eristada lugemis- ja kirjutamistegevused liidese tasemel. Tulin selle juurde lĂ€bi Interface Segregation Principle, mis nĂ€itab, et ma oskan mustrite ja pĂ”himĂ”tetega oskuslikult manipuleerida ning tuua ĂŒhe teisest vĂ€lja nagu teoreemi đ Loomulikult ei ole iga projekt vajab sellist abstraktsiooni entiteetide pĂ€ringute jaoks, kuid jagan teiega nippe. Rakenduse arendamise alguses vĂ”ib lihtsalt luua klassi PostQueries tavalise rakendusega Eloquenti kaudu:
<?php
final class PostQueries
{
public function getById($id): Post
{
return Post::findOrFail($id);
}
// teised meetodid
}Kui tekib vajadus vahemĂ€llu salvestada, vĂ”ib hĂ”lpsasti luua liidese (vĂ”i abstraktse klassi) selle klassi asemel PostQueries, kopeeri tema rakendus klassi ja kontrollers tĂ€iendab seda klassi. ja minna tagasi skeemile, mida ma varem kirjeldasin. ĂlejÀÀnud rakenduse koodi ei ole vaja muuta.
KÔik need nipid klasside ja liideste osas SÔltuvuse sisestamine ja CQRS on pÔhjalikult kirjeldatud . Samuti seal on mÔistatus, miks kÔik minu klassid selle artikli nÀidetes on mÀrgitud kui final.
Allikas: habr.com
