Java javë shkrova , por premtova të tregoj si mund të përdoret pjesërisht me përfitim. Për këtë do të përpiqem të analizoj si zakonisht përdoret ky model në projekte. Grupi minimal i metodave për repo:
<?php
interface PostRepository
{
public function getById($id): Post;
public function save(Post $post);
public function delete($id);
}Megjithatë, në projekte reale, nëse është vendosur të përdoren repos, shpesh shtohen metoda për marrjen e regjistrimeve:
<?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);
}KĂ«to metoda mund tĂ« realizohen pĂ«rmes Eloquent scopes, por mbingarkimi i klasave tĂ« entiteteve me detyra pĂ«r marrjen e vetvetes â nuk Ă«shtĂ« njĂ« ide e mirĂ« dhe kalimi i kĂ«saj detyre nĂ« klasat e repos duket logjik. A Ă«shtĂ« kĂ«shtu? UnĂ« e kam ndarĂ« kĂ«tĂ« interface nĂ« dy pjesĂ«. Pjesa e parĂ« e metodave do tĂ« pĂ«rdoret nĂ« operacionet e shkrimit.
Operacionet standarde të shkrimit janë:
- ndërtimi i një objekti të ri dhe thirrja PostRepository::save
- PostRepository::getById, manipulimet me entitetin dhe thirrja PostRepository::save
- thirrja PostRepository::delete
NĂ« operacionet e shkrimit nuk ka pĂ«rdorim tĂ« metodave tĂ« marrjes. NĂ« operacionet e leximit megjithatĂ« pĂ«rdoren vetĂ«m metodat get*. NĂ«se e lexoni mbi Principin e Ndarje tĂ« Interface-it (shkronja I nĂ« SOLID), do tĂ« kuptoni se interface-i ynĂ« rezultoi shumĂ« i madh dhe po realizon tĂ« paktĂ«n dy detyra tĂ« ndryshme. ĂshtĂ« koha ta ndajmĂ« nĂ« dy. Metoda getById nevojitet nĂ« tĂ« dyja, megjithatĂ« me komplikimin e aplikacionit realizimet e tij do tĂ« jenĂ« tĂ« ndryshme. KĂ«tĂ« do ta shohim mĂ« vonĂ«. PĂ«r pafajĂ«sinĂ« e pjesĂ«s write kam shkruar nĂ« artikullin e kaluar, prandaj pĂ«r kĂ«tĂ« nĂ« kĂ«tĂ« do ta harroj tĂ«rĂ«sisht.
Pjesa Read më duket se nuk është aq e pafajshme, pasi edhe për Eloquent këtu mund të ketë disa realizime. Si ta quajmë klasën? Mund të jetë ReadPostRepository, por me modelin Repository ai ka shumë pak lidhje. Mund ta quajmë thjesht PostQueries:
<?php
interface PostQueries
{
public function getById($id): Post;
public function getLastPosts();
public function getTopPosts();
public function getUserPosts($userId);
}Realizimi i tij me Eloquent është mjaft i thjeshtë:
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();
}
}Interface-i duhet të lidhet me realizimin, për shembull në AppServiceProvider:
app->bind(PostQueries::class,
EloquentPostQueries::class);
}
}Kjo klasë është tashmë e dobishme. Ajo përmbush përgjegjësinë e saj, duke lehtësuar ose kontrolluesit ose klasën e entitetit. Në kontrollues mund të përdoret kështu:
$postQueries->getLastPosts(),
]);
}
} Metoda PostsController::lastPosts thjesht kërkon ndonjë realizim të PostsQueries dhe punon me të. Në ofruesin ne lidhëm PostQueries me klasën EloquentPostQueries dhe në kontrollues do të vendoset kjo klasë.
Le tĂ« imagjinojmĂ« se aplikacioni ynĂ« Ă«shtĂ« bĂ«rĂ« shumĂ« popullor. MijĂ«ra pĂ«rdorues nĂ« minutĂ« hapin faqen me publikimet mĂ« tĂ« fundit. Publikimet mĂ« tĂ« njohura gjithashtu lexohen shumĂ« shpesh. Bazat e tĂ« dhĂ«nave nuk pĂ«rballen mirĂ« me kĂ«to ngarkesa, prandaj pĂ«rdorin zgjidhjen standarde â cache. PĂ«rveç bazĂ«s sĂ« tĂ« dhĂ«nave, njĂ« impresion tĂ« tĂ« dhĂ«nave ruhet nĂ« njĂ« magazinĂ« tĂ« optimizuar pĂ«r operacione tĂ« caktuara â memcached ose redis.
Logjika e caching zakonisht nuk Ă«shtĂ« aq e komplikuar, por zbatimi i saj nĂ« EloquentPostQueries nuk Ă«shtĂ« shumĂ« i drejtĂ« (tĂ« paktĂ«n pĂ«r shkak tĂ« Principit tĂ« pĂ«rgjegjĂ«sisĂ« sĂ« vetme). ĂshtĂ« shumĂ« mĂ« natyrale tĂ« pĂ«rdoret modelimi Dekorator dhe tĂ« realizohet caching si dekorim i veprimit kryesor:
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();
});
}
// metodat e tjera janë praktikisht të njëjta
}Mos e vini re interface-in Repository në konstruktor. Për arsye të panjohura kështu u vendos të quhej interface-i për caching në Laravel.
Klasa CachedPostQueries implementon vetëm caching. $this->cache->remember kontrollon nëse ky regjistrim është në cache dhe, nëse jo, thërret callback dhe ruan vlerën e kthyer në cache. Na mbetet vetëm ta integrojmë këtë klasë në aplikacion. Na nevojitet që të gjitha klasat që në aplikacion kërkojnë implementimin e ndërfaqes PostQueries të fillojnë të marrin një instancë të klasës CachedPostQueries. Por vetë CachedPostQueries si parametër në konstruktor duhet të marrë klasën EloquentPostQueries, sepse nuk mund të punojë pa një implementim "të vërtetë". Ndryshojmë AppServiceProvider:
app->bind(PostQueries::class,
CachedPostQueries::class);
$this->app->when(CachedPostQueries::class)
->needs(PostQueries::class)
->give(EloquentPostQueries::class);
}
}Të gjitha dëshirat e mia përshkruhen mjaft natyrshëm në ofrues. Kështu, ne implementuam cache për kërkesat tona vetëm duke shkruar një klasë dhe duke ndërruar konfigurimin e konteinerit. Kodi i pjesës tjetër të aplikacionit nuk ndryshoi.
Natyrisht, për një implementim të plotë të caching, gjithashtu duhet të implementohet invalideimi, në mënyrë që artikulli i fshirë të mos mbetet në faqe për ndonjë kohë tjetër dhe të fshihet menjëherë. Por këto janë detaje të vogla.
PĂ«rmbledhje: ne pĂ«rdorĂ«m jo njĂ«, por dy modele. Modeli Command Query Responsibility Segregation (CQRS) propozoni tĂ« ndahen plotĂ«sisht operacionet e leximit dhe shkruajtur nĂ« nivelin e ndĂ«rfaqeve. Arrita te ai Principin e Ndarje tĂ« Interface-it, qĂ« tregon se unĂ« manipulloj me modelet dhe parimet dhe nxjerr njĂ«rĂ«n nga tjetra si thĂ«nie đ Natyrisht, jo çdo projekt ka nevojĂ« pĂ«r njĂ« abstraksion tĂ« tillĂ« pĂ«r seleksionimin e entiteteve, por do tĂ« ndaj me ju njĂ« truk. NĂ« fazĂ«n fillestare tĂ« zhvillimit tĂ« aplikacionit mund tĂ« krijoni thjesht njĂ« klasĂ« PostQueries me njĂ« implementim tĂ« zakonshĂ«m pĂ«rmes Eloquent:
<?php
final class PostQueries
{
public function getById($id): Post
{
return Post::findOrFail($id);
}
// metoda të tjera
}Kur të lindë nevoja për cache, me një lëvizje të lehtë mund të krijosh një ndërfaqe (ose klasë abstrakte) në vend të kësaj klase PostQueries, implementimin e saj të kopjojmë në klasën EloquentPostQueries dhe të kalojmë në skemën e përshkruar më parë. Kodi tjetër i aplikacionit nuk duhet të ndryshojë.
Të gjitha këto truke me klasat, ndërfaqet, Injektimi i varësisë dhe CQRS përshkruhen në detaje në . Atje gjithashtu ndodhet zgjidhja e misterit pse të gjitha klasat e mia në shembujt e kësaj artikulli janë shënuar si final.
Burimi: habr.com
