آموزش لاراول - Facade چیست و چرا باید از آن استفاده کرد؟

اگر شخصی به شما گفت که لاراول بلده ولی تا حالا facade به گوشش نخورده و یا نمی‌دونه چیه! مطمئین باشید، بلد نیست!!! شاید شما درمورد الگو‌های طراحی (Design Pattern) و اهمیت آن‌ها شنیده باشید. بطور‌کلی الگوهای طراحی مختلفی وجود داره تا شما با کمک اونها بتوانید کدهای خواناتر و یا اصطلاحا تمیزتری بنویسید. Facade یکی از همین الگوهاست.

در این مقاله قصد دارم شمارو با مفهوم الگوی Facade آشنا کنم و از ابتدا در یک مثال قوائد این الگو رو پیاده‌سازی کنم.


خب برای شروع من یک پروژه خام لاراول رو نصب کردم و قصد دارم در اون یک کلاس فوق ساده برای ارسال تیکت پیاده‌سازی کنم:

Image for post
Image for post

همانطور که مشاهده می‌کنید در این کلاس mailer توسط سازنده تعریف شده است. در مورد نحوه کار با ایمیل و پیاده‌سازی اون هم می‌تونید به مقاله دیگری که در این رابطه آموزش دادم مراجه بکنید:

خب حالا اگر بخواهیم از این کلاس استفاده کنیم. کار بسیار سادست کافیه یک شی از این کلاس ایجاد کنید و درنهایت تابع send رو همراه با مقداردهی آرگومان‌هایی که لازم داره فراخوانی کنید:

$ticket = new TicketService(TicketMail::class);
$ticket->send('abs@abc.com', 'Hello abs, THIS IS A TICKET');

در این آموزش خواهید دید که چطور این کلاس رو با کمک الگوی facade بازنویسی می‌کنیم.

اما پیش از شروع اجازه دهید که با مفاهیمی که در این الگو وجود داره بیشتر آشنا بشیم تا دلیل این نوع از طراحی رو بهتر درک کنیم. برای این منظور من یک کلاس دیگری به نام Ticket ایجاد کردم حالا اگر یک متد static از این کلاس که وجود نداره رو فراخوانی کنیم قطعا با خطا مواجه میشیم! درسته؟!

Ticket::something('abc', 'def');

>>> Call to undefined method App\Services\Ticket::something()

اما یک تابع عجیب دیگر به نام callStatic_ وجود داره که می‌تونه نام و حتی آرگومان‌هایی یک متد static از یک کلاس که حتی وجود خارجی نداره رو برگردونه. به کلاس Ticket برمی‌گردیم و تابع callStatic_ رو مشابه زیر تعریف می‌کنیم: 

Image for post
Image for post

حالا اگه تابع something یا هرچیز دیگری رو صدا کنید خروجی زیر رو خواهید داشت:

Image for post
Image for post

این یکی از مهمترین قسمت‌های یک الگوی Facade است. 

در گام بعدی کلاس TicketService رو در کانتینر اصلی پروژمون یعنی app با کلید 'ticket' درج می‌کنیم. درصورتیکه با مفاهیم پایه‌ای Service Container و Providers ها آشنا نیستید پیشنهاد می‌کنم حتما مقاله دیگری که در این رابطه نوشتم رو مطالعه کنید:

خب برای تعریف TicketService به AppServiceProvider و متد boot برید و بصورت زیر تعریف کنید:

Image for post
Image for post

حالا اگر کانتینر اصلی پروژه لاراولیمون رو با کمک تابع کمکی app نگاه کنیم خواهیم دید که در اون تمامی ابزاری‌هایی که لاراول نیاز داره وجود داره همانطور هم که در قسمت binding در تصویر زیر مشاهده می‌کنید کلاس ما با کلید ticket در اون وجود داره:

Image for post
Image for post

اما همانطور که قبلا هم اشاره شد برای دریافت نمونه‌ای از کلاسی که در کانتینر تعریف کردیم می‌توانستیم با تابع make آنرا دریافت کنیم. یک روش دیگر هم وجود داره که مشابه کار با آرایه‌هاست و ساده‌تره در هر حالت فرقی نداره هردو روش یک نمونه از کلاس رو خواهند داد:

app()->make('ticket');

// or 

app()['ticket'];

براساس آنچه گفته شد من تابع static دیگری برای دریافت نمونه‌ای که با کمک service در پروژمون وارد کرده بودیم در کلاس Ticket نوشتم و نهایتا این کلاس رو بصورت زیر بازنویسی کردم:

Image for post
Image for post

موردی که اینجا وجود داره کلمه کلیدی self هست که اگر با برنامه‌نویسی شی‌گرا آشنا باشید می‌دونید که زمانی که یک متد static از یک کلاس رو فراخوانی می‌کنیم ازآنجایی که نمونه‌ای از کلاس در دسترس نیست پس نمی‌تونیم از کلمه this استفاده کنیم بنابراین در اینجا از self استفاده شده. مورد دیگه نحوه فراخوانی با متغیر method$ هست بطور کلی از این روش جاهایی که تابع بصورت داینامیک قرار هست انتخاب بشه کاربرد داره. در نهایت هم عملگر ... هست که به عملگر slapt معروفه و از PHP 5.6 اضافه شد و بیشتر جاهایی کاربرد داره که شما می‌خواهید تعداد متغیری آرگومان برای یک متد تعریف کنید. من در اینجا آرایه که تابع callStatic_ برای آرگمان‌ها برمیگردونه رو اصطلاحا unpack کردم و برای تابع مورد نظرمون ارسال می‌کنم.

خب حالا بیایید یکبار مرور کنیم فرایندی که اینجا اتفاق میفته:

  1. فرض کنیم ابتدا بصورت static تابع send رو روی کلاس Ticket صدا زدید
  2. تابع  callStatic_ ابتد میاد با متد resolveFacade کلاسی که با کلید 'ticket' در کانتینر پروژه وجود داره رو می‌گیره که در اینجا همون TicketService هست
  3. درنهایت هم بعد از گرفتن کلاس بصورت داینامیک تابع send با آرگومان‌هایی که unpack کردیم فراخوانی میشه

 

حالا بسادگی تنها با صدا زدن تابع send روی کلاس Ticket عملیات ارسال ایمیل با موفیت انجام میشه:

Ticket::send('abs@abc.com', 'Hello abs, THIS IS A TICKET');

 

تبریک می‌گم این همان الگوی Facade هست که لاراول از اون استفاده می‌کنه و شما حالا با مفهوم و کارکرد این الگوی طراحی آشنا شدید. حالا زمانی که دارید با کلاس‌های از پیش‌ تعریف شده لاراول که Facade هستند، کار می‌کنید مانند کلاس Route متوجه سازکاری که در پشت این کلاس‌هاست خواهید بود. 


اما برای اینکه یک کلاس Facade بشه لازم نیست قواعدی که در این آموزش توضیح دادیم هربار به کلاس‌هایمان اضافه کنیم. برای اینکار راهکار ساده‌تری وجود داره و اون استفاده کردن خاصیت Facade که خود لاراول توسعه داده هست.

برای اینکار تنها کافیه دو اقدام انجام دهید:

۱. تعریف کلاس جدیدی که از Facade لاراول ارث‌بری می‌کنه:

Image for post
Image for post

2. تعریف کلاس TicketService رو در کانتینر اصلی پروژمون یعنی app با کلید 'ticket' که البته در این آموزش اینکار رو انجام داده‌ بودیم.

 

حالا اگر به route/web.php جایی که کدهامون رو تست می‌کنیم برگردید مشاهده خواهید کرد حتی با حذف قسمت مربوط به وارد کردن کلاس Test در این فایل کد همچنان کار می‌کنه چرا که ما اینبار نام این کلاس رو بصورت facade در کانتینر اصلی وارد کردیم:

<?php

use Illuminate\Support\Facades\Route;

Route::get('/facade', function () {
    Ticket::send('abs@abc.com', 'Hello abs, THIS IS A TICKET');
});

 


امیدوارم از این آموزش هم لذت برده باشید!

کدهای مربوط به این آموزش هم در گیت‌هاب می‌تونید مشاهده کنید: