تاحالا شده یکسری دستورات تکراری رو هرجایی از پروژتون استفاده کنید و دیگه خسته شده باشید ازش؟ من مثل شما، فقط از این که کد ها تکراری باشه خسته نشده بودم، به هم ریختگی بیشتر اذیتم میکرد.
داشتم اینترنت رو زیر و رو میکردم نه برای پیدا کردن راهی، برای یادگرفتن چیز های جدید.
تصمیم گرفتم برم چندتا دیزاین پترن دیگه یادبگیرم
دیزاین پترنها به من بیشتر از برنامهنویسی سبک فکر کردن رو یاد میدند!
از دیزاین پترنهای ساده شروع کردم، یک پترن جالب پیدا کردم به اسم Decorator کارش این بود که یکسری تغییرات رو به صورت سلسله مراتب روی ورودی انجام بده و خروجی نهایی رو برگردونه. کارش خیلی باحاله، مثلا شما یه متن دارید قراره کار های زیر رو به ترتیب روش اعمال کنید.
۱. حذف کلمات رکیک
۲. حذف نماد های اضافه
۳. حذف فاصله های اضافه
۴. اضافه کردن نیمفاصله
میشه همه این قانین رو یکجا نوشت و توسعهاش روز به روز سخت تر و سختتر میشه یا بیایم از این دیزاین پترن استفاده کنیم.
?
دیاگرام بالا فقط برای درک بهتر هست، ما با همون متن پیش میریم که ساده تر باشه
برای این دیزاین پترن به یک Interface نیاز داریم به این صورت
<?php namespace Rp۷۶\Decorator; interface Stringify { public function operation(): string; }
حالا یک Class باید داشته باشیم به عنوان کلاس اصلی که از این Interface ارث بری کنه.
<?php namespace Rp۷۶\Decorator; class MainData implements Stringify { public function operation(): string { return file_get_contents("file.txt"); } }
? اسم گذاری یکم سخته !!
خب class بالا اصل داستان هست و دیتا از اونجا وارد میشه حالا هر شیوهای که دوست دارید.
تا اینجا همون داستان قبلی هست، فرض کنید که MainData جمله رو گرفته و کلمات رکیک رو حذف کرده.
فردا دوباره میرید پای کار و میبینید که باید علامتهای اضافه هم پاک کنید.
یک class دیگه اضافه میکنم، از این جا داستان داره یکم عوض میشه!
<?php namespace Rp۷۶\Decorator; class Decorator implements Stringify { protected $component; public function __construct(Stringify $component) { $this->component = $component; } public function operation(): string { return $this->component->operation(); } }
class ما باید دوباره از interface ارث بری کنه و یک متد سازنده یا Constructor داشته باشه که ورودیش یک کلاسی باشه که از همون interface ارث بری میکنه.
حالا وقت اون رسیده که قوانین رو بسازیم، هر قانون یک Class.
قوانین باید از کلاس بالا ارثبری کنند.
<?php namespace Rp۷۶\Decorator; class BadWords extends Decorator { public function operation(): string { return str_replace("some_bad_words","****",parent::operation()); } }
<?php namespace Rp۷۶\Decorator; class Emojis extends Decorator { public function operation(): string { return str_replace("some_emoji","",parent::operation()); } }
خب حالا چطوری استفاده کنیم؟ خیلی ساده هست!
<?php namespace Rp۷۶\Decorator; $decorator=new MainData; echo $decorator->operation();
خب کد بالا متن خام رو برمیگردونه مثل روز اول، اگر میخواید که قوانین اعمال بشه باید کد زیر رو استفاده کنید.
<?php namespace Rp۷۶\Decorator; $decorator=new MainData; $decorator۱=new BadWords($decorator); $decorator۲=new Emojis($decorator۱); echo $decorator۲->operation();
به همین صورت میشه میلیون ها قانون دیگه اضافه کرد بدون این که هر کدوم به هم وابستگی خاصی داشته باشند.
توی لاراول از این پترن هم استفاده شده، اگر بخواید توی لاراول همچین چیزی داشته باشد میتونید از کلاس \Illuminate\Pipeline\Pipeline::class استفاده کنید که کار رو خیلی ساده کرده.
متدهای این کلاس شامل
به ۲ حالت میشه ازش استفاده کرد.
app(\Illuminate\Pipeline\Pipeline::class) ->send("salam") ->through([ Class۱::class, Class۲::class, . . . ])->thenReturn();
یا
$pipe=null \Illuminate\Pipeline\Pipeline(); $pipe->send("salam") ->through([ Class۱::class, Class۲::class, . . . ])->thenReturn();
توی نگاه اول میگید خب اولی بهتره و قطعا دلیل اصلیتون اینه که به پایپ لاراول نمیشه دیتایی ارسال کرد، باید بگم که اشتباه میکنید برای ارسال پارامتر اضافه میشه توی متد سازنده کلاس ها ورودی رو بگیرید و بدید به پایپ به این صورت
$pipe=null \Illuminate\Pipeline\Pipeline(); $pipe->send("salam") ->through([ new Class۱($param), new Class۲($param,$arg) ])->thenReturn();
این پایپ خیلی دستمون رو باز گذاشته حتی میتونید بهش فانکشن هم پاس بدید و نیاز به کلاس نداشته باشید.
$pipe=null \Illuminate\Pipeline\Pipeline(); $pipe->send("salam") ->through([ function($content,\Closure $next){ return $neext($content); }, function($content,\Closure $next){ return $neext($content); } ])->thenReturn();
داشت یادم میرفت اگر خواستید کلاسی به این پایپ ارسال کنید حتما متد handle رو ایجاد کنید یا با متد via متد خودتون رو معرفی کنید.
این متد ۲تا ورودی داره یکی رو از شما میگیره که همون مقداری هست که به send دادید و ورودی دوم هم یک فانکشن هست که وظیفه انتقال اطلاعات رو برعده داره.