لاراول در لولهکشی Decorator
تاحالا شده یکسری دستورات تکراری رو هرجایی از پروژتون استفاده کنید و دیگه خسته شده باشید ازش؟ من مثل شما، فقط از این که کد ها تکراری باشه خسته نشده بودم، به هم ریختگی بیشتر اذیتم میکرد.
داشتم اینترنت رو زیر و رو میکردم نه برای پیدا کردن راهی، برای یادگرفتن چیز های جدید.
تصمیم گرفتم برم چندتا دیزاین پترن دیگه یادبگیرم
دیزاین پترنها به من بیشتر از برنامهنویسی سبک فکر کردن رو یاد میدند!
از دیزاین پترنهای ساده شروع کردم، یک پترن جالب پیدا کردم به اسم 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 استفاده کنید که کار رو خیلی ساده کرده.
متدهای این کلاس شامل
-
Send ورودی ما به Pipe هست برای پرداشز
-
through ورودی ما از طریق این متد که یک آرایه ای از کلاس هارو به عنوان ورودی میگیره پردازش میشه.
-
via این متد هم یک اسم از ما میگیره به عنوان اسم متدی که توی کلاس های بالا باید صدا زده بشه که به صورت پیشفرض روی handle تنظیم شده.
-
then بعد از این که پردازش ها تموم شد این متد صدا زده میشه که یک فانکشن به عنوان ورودی میخواد و نتیجه رو به اون فانکشن پاس میده.
-
thenReturn اگر توی کلاس اصلی بهش نگاه متوجه میشید که دقیقا متد بالا رو صدا زده و نتیجه رو توی ورودیش برگردونده.
به ۲ حالت میشه ازش استفاده کرد.
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 دادید و ورودی دوم هم یک فانکشن هست که وظیفه انتقال اطلاعات رو برعده داره.
چون مینویسم هستم.
🤯 1
😍 3
😁 2
😬 2
😊 2
🤨 3
🙁 3
🥲 3
😭 3
😡 2
🤬 1