PagÄjuÅ”ajÄ nedÄÄ¼Ä es rakstÄ«ju tomÄr viÅÅ” apsolÄ«ja man pastÄstÄ«t, kÄ to daļÄji izmantot savÄ labÄ. Lai to izdarÄ«tu, es mÄÄ£inÄÅ”u analizÄt, kÄ Å”Ä« veidne parasti tiek izmantota projektos. Repozitorija minimÄlais nepiecieÅ”amais metožu kopums:
<?php
interface PostRepository
{
public function getById($id): Post;
public function save(Post $post);
public function delete($id);
}TomÄr reÄlos projektos, ja tika nolemts izmantot repozitorijus, tiem bieži tiek pievienotas ierakstu izguves metodes:
<?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);
}Å Ä«s metodes varÄtu ieviest, izmantojot Eloquent tvÄrumus, taÄu pÄrslogot entÄ«tiju klases, uzÅemoties paÅ”as par sevi, nav labÄkÄ ideja, un Ŕīs atbildÄ«bas pÄrvietoÅ”ana uz repozitoriju klasÄm Ŕķiet loÄ£iska. Vai tÄ ir? Es Ä«paÅ”i vizuÄli sadalÄ«ju Å”o saskarni divÄs daļÄs. PirmÄ metožu daļa tiks izmantota rakstīŔanas operÄcijÄs.
Standarta rakstīŔanas darbÄ«ba ir Å”Äda:
- jauna objekta celtniecÄ«ba un izaicinÄjums PostRepository::save
- PostRepository::getById, entÄ«tiju manipulÄcijas un izsaukÅ”ana PostRepository::save
- izaicinÄjums PostRepository::delete
RakstīŔanas operÄcijÄs netiek izmantotas ielÄdes metodes. LasīŔanas operÄcijÄs tiek izmantotas tikai get* metodes. Ja lasi par Interfeisa segregÄcijas princips (vÄstule I в SOLID), tad kļūs skaidrs, ka mÅ«su saskarne ir pÄrÄk liela un veic vismaz divus dažÄdus pienÄkumus. Ir pienÄcis laiks to sadalÄ«t ar diviem. Metode getById ir nepiecieÅ”ama abos, taÄu, lietojumprogrammai kļūstot sarežģītÄkai, tÄs ievieÅ”anas bÅ«s atŔķirÄ«gas. To mÄs redzÄsim nedaudz vÄlÄk. Es rakstÄ«ju par rakstīŔanas daļas bezjÄdzÄ«bu iepriekÅ”ÄjÄ rakstÄ, tÄpÄc Å”ajÄ es par to vienkÄrÅ”i aizmirsīŔu.
LasīŔanas daļa man neŔķiet tik bezjÄdzÄ«ga, jo pat Eloquent Å”eit var bÅ«t vairÄkas ievieÅ”anas. KÄ nosaukt klasi? Var ReadPostRepository, bet uz veidni KrÄtuve viÅam jau ir maza nozÄ«me. JÅ«s varat vienkÄrÅ”i PostQuerys:
<?php
interface PostQueries
{
public function getById($id): Post;
public function getLastPosts();
public function getTopPosts();
public function getUserPosts($userId);
}To ieviest ar Eloquent ir pavisam vienkÄrÅ”i:
<?php
final class EloquentPostQueries implements PostQueries
{
public function getById($id): Post
{
return Post::findOrFail($id);
}
/**
* @return Post[] | Collection
*/
public function getLastPosts()
{
return Post::orderBy('created_at', 'desc')
->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();
}
}Saskarnei jÄbÅ«t saistÄ«tai ar ievieÅ”anu, piemÄram, in AppServiceProvider:
<?php
final class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(PostQueries::class,
EloquentPostQueries::class);
}
}Å Ä« klase jau ir noderÄ«ga. ViÅÅ” apzinÄs savu atbildÄ«bu, atbrÄ«vojot vai nu kontrolierus, vai entÄ«tiju klasi. KontrolerÄ« to var izmantot Å”Ädi:
<?php
final class PostsController extends Controller
{
public function lastPosts(PostQueries $postQueries)
{
return view('posts.last', [
'posts' => $postQueries->getLastPosts(),
]);
}
} Metode PostsController::lastPosts tikai prasu kÄdu ievieÅ”anu PostsQuerys un strÄdÄ ar to. MÅ«su piesaistÄ«tajÄ pakalpojumu sniedzÄjÄ PostQuerys ar klasi EloquentPostQueries un Ŕī klase tiks aizstÄta ar kontrolieri.
IedomÄsimies, ka mÅ«su aplikÄcija ir kļuvusi ļoti populÄra. TÅ«kstoÅ”iem lietotÄju minÅ«tÄ atver lapu ar jaunÄkajÄm publikÄcijÄm. Ä»oti bieži tiek lasÄ«tas arÄ« populÄrÄkÄs publikÄcijas. Datu bÄzes ar Å”ÄdÄm slodzÄm netiek galÄ Ä«paÅ”i labi, tÄpÄc izmanto standarta risinÄjumu ā keÅ”atmiÅu. Papildus datu bÄzei noteikts datu momentuzÅÄmums tiek glabÄts krÄtuvÄ, kas ir optimizÄts noteiktÄm darbÄ«bÄm - memcached vai Redis.
KeÅ”atmiÅas loÄ£ika parasti nav tik sarežģīta, taÄu tÄs ievieÅ”ana programmÄ EloquentPostQueries nav pÄrÄk pareiza (ja tikai tÄpÄc, ka Vienotas atbildÄ«bas princips). Daudz dabiskÄk ir izmantot veidni Dekorators un ieviest keÅ”atmiÅu kÄ galvenÄs darbÄ«bas noformÄjumu:
<?php
use IlluminateContractsCacheRepository;
final class CachedPostQueries implements PostQueries
{
const LASTS_DURATION = 10;
/** @var PostQueries */
private $base;
/** @var Repository */
private $cache;
public function __construct(
PostQueries $base, Repository $cache)
{
$this->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();
});
}
// Š“ŃŃŠ³ŠøŠµ Š¼ŠµŃŠ¾Š“Ń ŠæŃŠ°ŠŗŃŠøŃŠµŃŠŗŠø ŃŠ°ŠŗŠøŠµ же
}IgnorÄjiet saskarni KrÄtuve konstruktorÄ. NezinÄma iemesla dÄļ viÅi nolÄma Å”Ädi nosaukt Laravel keÅ”atmiÅas interfeisu.
Klase CachedPostQueries ievieÅ” tikai keÅ”atmiÅu. $this->cache->atcerÄties pÄrbauda, āāvai Å”is ieraksts ir keÅ”atmiÅÄ un ja nav, tad izsauc atzvanīŔanu un ieraksta atgriezto vÄrtÄ«bu keÅ”atmiÅÄ. Atliek tikai ieviest Å”o klasi lietojumprogrammÄ. Mums ir vajadzÄ«gas visas lietojumprogrammas klases, lai pieprasÄ«tu saskarnes ievieÅ”anu PostQuerys sÄka saÅemt klases piemÄru CachedPostQueries. TomÄr viÅÅ” pats CachedPostQueries konstruktoram kÄ parametrs jÄsaÅem klase EloquentPostQueriesjo tas nevar darboties bez "Ä«stas" ievieÅ”anas. MÄs mainÄmies AppServiceProvider:
<?php
final class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(PostQueries::class,
CachedPostQueries::class);
$this->app->when(CachedPostQueries::class)
->needs(PostQueries::class)
->give(EloquentPostQueries::class);
}
}Visas manas vÄlmes ir diezgan dabiski aprakstÄ«tas pakalpojumu sniedzÄjÄ. TÄdÄjÄdi mÄs ieviesÄm keÅ”atmiÅu saviem pieprasÄ«jumiem, tikai rakstot vienu klasi un mainot konteinera konfigurÄciju. PÄrÄjais lietojumprogrammas kods nav mainÄ«jies.
Protams, lai pilnÄ«bÄ ieviestu keÅ”atmiÅu, ir jÄievieÅ” arÄ« nederÄ«ba, lai dzÄstais raksts kÄdu laiku nekarÄtos vietnÄ, bet tiktu nekavÄjoties izdzÄsts. Bet tÄs ir mazsvarÄ«gas lietas.
SecinÄjums: mÄs izmantojÄm nevis vienu, bet divas veidnes. Paraugs Command Query Responsibility Segregation (CQRS) ierosina pilnÄ«bÄ nodalÄ«t lasīŔanas un rakstīŔanas darbÄ«bas saskarnes lÄ«menÄ«. Es nonÄcu pie viÅa caur Interfeisa segregÄcijas princips, kas liek domÄt, ka es prasmÄ«gi manipulÄju ar modeļiem un principiem un atvasinu vienu no otra kÄ teorÄmu :) Protams, ne katram projektam ir vajadzÄ«ga Å”Äda entÄ«tiju atlases abstrakcija, bet es padalīŔos ar jums. attÄ«stÄ«bu, varat vienkÄrÅ”i izveidot klasi PostQuerys ar parasto ievieÅ”anu, izmantojot Eloquent:
<?php
final class PostQueries
{
public function getById($id): Post
{
return Post::findOrFail($id);
}
// Š“ŃŃŠ³ŠøŠµ Š¼ŠµŃŠ¾Š“Ń
}Kad rodas vajadzÄ«ba pÄc keÅ”atmiÅas, ar vienkÄrÅ”u pÄrvietoÅ”anu varat izveidot interfeisu (vai abstraktu klasi) Ŕīs klases vietÄ PostQuerys, kopÄjiet tÄ ievieÅ”anu klasÄ EloquentPostQueries un dodieties uz iepriekÅ” aprakstÄ«to shÄmu. PÄrÄjais lietojumprogrammas kods nav jÄmaina.
Visi Å”ie triki ar klasÄm, saskarnÄm, AtkarÄ«bas injekcija Šø CQRS detalizÄti aprakstÄ«ts . Ir arÄ« risinÄjums mÄ«klai, kÄpÄc visas manas nodarbÄ«bas Ŕī raksta piemÄros ir atzÄ«mÄtas kÄ galÄ«gas.
Avots: www.habr.com
