همونطور که می دونیم تو دنیای توسعه نرم فزار، اصول SOLID به برنامهنویسا کمک میکنن تا کدی بنویسن که نگهداری، مدیریت و گسترشش راحتتر باشه.
لاراول، با سینتکس زیبا و قابلیتهای قویش، یه بستر عالی برای اجرای این اصول به حساب میاد. توی این مطلب سعی می کنم اصول SOLID رو از دیدگاه لاراول بگم و شما رو با روش استفاده از این اصول توی فریم وورک لاراول آشنا کنم.
اصول SOLID چی هستن:
SOLID یه مخفف از پنج اصل طراحی هست که هدفشون اینه طراحیهای نرمافزاری رو قابل فهمتر، انعطافپذیرتر و نگهداریشون رو آسونتر کنه. وقتی این اصول رو بررسی میکنیم، میبینیم که چطور لاراول نه تنها این اصول رو پذیرفته، بلکه از طریق ویژگیها و معماریش، به خوبی اونا رو اجرا میکنه.
۱. اصل مسئولیت یگانه (SRP) یا Single Responsibility Principle
یه کلاس باید فقط یه دلیل برای تغییر داشته باشه، یعنی باید فقط یه وظیفه یا مسئولیت داشته باشه.
SRP مثل یه آشپز توی آشپزخونهست — یه آشپز، یه غذا. این اصل میگه همونطور که یه آشپز تمرکزش روی درست کردن یه نوع غذاست، هر کلاس تو کدت باید فقط روی یه جنبه از نرمافزار تمرکز کنه. این رویکرد کد رو قابل مدیریت، اشکالزدایی و بروزرسانی میکنه.
مثال:
کنترلرها باید فقط مدیریت درخواستهای HTTP رو انجام بدن و منطق کسبوکار رو به کلاسهای دیگه مثل سرویسها بسپارن. اینطوری کنترلرها تمیز و کد قابل نگهداری میمونه:
namespace App\Http\Controllers;
use App\Services\UserService;
class UserController extends Controller
{
protected $userService;
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
public function index()
{
return $this->userService->getAllUsers();
}
}
لاراول از اصل SRP در طراحی خودش استفاده میکنه، به ویژه توی تنظیمات مسیریابی و کنترلرها. مسیریابیها توی فایلهای web.php یا api.php تعریف میشن و فقط روی مسائل مربوط به مسیریابی تمرکز دارن، در حالی که کنترلرها درخواستهای HTTP رو مدیریت میکنن و منطق کسبوکار رو به سرویسها یا مدلها میسپارن، که این جداسازی باعث تمیزی کد و نگهداری آسونتر میشه.
۲. اصل باز/بسته (OCP) Open/Closed Principle
کلاس ها باید برای توسعه باز ولی برای تغییر بسته باشن. این یعنی میتونین قابلیتهای جدید اضافه کنید بدون اینکه کد موجود رو تغییر بدین!
مثل یه جعبه آبرنگ! مثلا میتونی رنگهای جدید به پالت اضافه کنی بدون اینکه رنگهای موجود رو تغییر بدی! اصل OCP میگه باید کلاسها رو طوری طراحی کنید که بتونید قابلیتهای جدید اضافه کنید بدون اینکه کارکرد موجود رو تغییر بدین، که این باعث انعطافپذیری و آسونتر شدن نگهداری میشه.
مثلا توی لاراول میتونی با استفاده از سرویس پروایدر ها، قابلیتهای لاراول رو گسترش بدی و از اصل OCP پیروی کنی:
namespace App\Providers;
use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Notifications\Messages\MailMessage;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
ResetPassword::toMailUsing(function ($notifiable, $token) {
$url = url(route('password.reset', [
'token' => $token,
'email' => $notifiable->getEmailForPasswordReset(),
], false));
return (new MailMessage)
->subject('Reset Password Notification')
->line('You are receiving this email because we received a password reset request for your account.')
->action('Reset Password', $url)
->line('If you did not request a password reset, no further action is required.');
});
}
}
لاراول به طور گستردهای از اصل OCP در معماری خودش استفاده میکنه، به خصوص با package ها، رویدادها و میان فزارها. شما میتونید ویژگیهای جدید اضافه یا تغییر بدن بدون اینکه رفتار اصلی فریمورک رو تغییر کنه، که این تضمین میکنه که اجزای اصلی بدون تغییر باقی میمونن در حالی که قابلیتهای جدید به صورت یکپارچه اضافه میشن.
۳. اصل جایگزینی لیسکوف (LSP) Liskov Substitution Principle
اشیاء یک کلاس پدر باید بتوانند با اشیاء کلاسهای فرزند جایگزین بشن بدون اینکه درستی برنامه تحت تأثیر قرار گیرد.
تصور کن یه دستگاه قهوهساز داری با درصد ها و نوع های مختلف قهوه. باید بتونی هر کپسول قهوه رو (کلاس فرزند) توی اون دستگاه (کلاس پدر) استفاده کنی بدون اینکه خراب بشه.
از دید کدنویسی، این اصل میگه یه کلاس فرزند باید جایگزین کلاس پدرش بشه بدون اینکه رفتار برنامه رو تغییر بده.
توی لاراول، میتونی پیادهسازیها رو برای یک قرارداد (interface) بدون مشکل جایگزین کنی:
namespace App\Contracts;
interface PaymentService
{
public function processPayment($amount);
}
namespace App\Services;
class PayPalService implements PaymentService
{
public function processPayment($amount)
{
// پردازش پرداخت از طریق PayPal
}
}
namespace App\Services;
class StripeService extends PayPalService
{
public function processPayment($amount)
{
// پردازش پرداخت از طریق Stripe، با اطمینان از پیروی از قرارداد PayPalService
}
}
function processPayment(PaymentService $service, $amount) {
$service->processPayment($amount); // StripeService میتواند بدون مشکل جایگزین PayPalService شود
}
کانتینر سرویس لاراول و مدلهای الکوئنت هر دو از اصل LSP پیروی میکنن. میتونید مدلهای پایه رو با کلاسهای فرزند تخصصی جایگزین کنی یا رابطها رو با پیادهسازیهای خاص در کانتینر جایگزین کنید.
۴. اصل جداسازی رابط (ISP) Interface Segregation Principle
یک مشتری نباید مجبور به پیادهسازی رابطهایی بشه که از اونها استفاده نمیکنه. به عبارت دیگه، رابطها رو کوچک و متمرکز نگه دار.
مثل منوی یه رستوران - افراد مختلف غذاهای مختلف سفارش میدن. اگه منو خیلی پیچیده باشه، ممکنه چیزهایی سفارش بدی که نیاز نداری. به همین ترتیب، این اصل پیشنهاد میکنه که رابطها رو به قراردادهای کوچکتر و خاصتر بشکنی تا کلاسها فقط اون چیزی رو که نیاز دارن پیادهسازی کنن.
مثال: به جای یه رابط بزرگ برای سیستم اعلان، رابطهای کوچکتر و متمرکزتر ایجاد کن:
namespace App\Contracts;
interface EmailNotifier
{
public function sendEmail($recipient, $message);
}
namespace App\Contracts;
interface SMSNotifier
{
public function sendSMS($number, $message);
}
namespace App\Services;
class EmailService implements EmailNotifier
{
public function sendEmail($recipient, $message)
{
// کد برای ارسال ایمیل
}
}
namespace App\Services;
class SMSService implements SMSNotifier
{
public function sendSMS($number, $message)
{
// کد برای ارسال پیامک
}
}
لاراول اصل ISP رو با استفاده از چندین رابط برای قسمتهای مختلف فریمورک، مثل Queueable، Renderable، و ShouldQueue رعایت میکنه. برنامهنویسا میتونن فقط ویژگیهای مورد نیاز رو پیادهسازی کنن بدون اینکه مجبور باشن همه چیز رو پیادهسازی کنن.
۵. اصل وارونگی وابستگی (DIP) Dependency Inversion Principle
این اصل میگه: ماژولهای سطح بالا نباید به ماژولهای سطح پایین وابسته باشن؛ هر دو باید به انتزاع وابسته باشن.
مثل یه پریز برق و شارژر دستگاه! مهم نیست چه شارژری استفاده میشه، باید همیشه به همون پریز بخوره. اصل DIP میگه به جای هاردکد کردن یک نوع شارژر، به یه آداپتور (interface) تکیه کن تا سیستم انعطافپذیر بمونه.
مثلا service container توی این اصل رو آسون میکنه با بایند کردن interface ها
namespace App\Contracts;
interface PaymentService
{
public function processPayment($amount);
}
namespace App\Services;
class PayPalService implements PaymentService
{
public function processPayment($amount)
{
// پردازش پرداخت از طریق PayPal
}
}
namespace App\Services;
class StripeService implements PaymentService
{
public function processPayment($amount)
{
// پردازش پرداخت از طریق Stripe
}
}
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Contracts\PaymentService;
use App\Services\StripeService;
class PaymentServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(PaymentService::class, StripeService::class);
}
}
service container لاراول یه پیادهسازی اساسی از اصل DIP هست، که اجازه میده وابستگیها رو از طریق رابطها تزریق کنیم به جای اینکه مستقیم به کلاسهای خاص وابسته باشیم. این رویکرد تضمین میکنه که منطق سطح بالا به انتزاع تکیه میکنه نه پیادهسازیها.
نتیجه گیری:
هر اصل SOLID به ما کمک میکنه تا کدی بنویسیم که مدولار، قابل پیشبینی و راحتتر قابل گسترش باشه.
- اصل مسئولیت یگانه (SRP) تضمین میکنه که هر کلاس یه نقش متمرکز داره.
- اصل باز/بسته (OCP) تشویق میکنه که بدون تغییر کد موجود، قابلیتهای جدید اضافه کنی.
- اصل جایگزینی لیسکوف (LSP) تضمین میکنه که کلاسهای فرزند میتونن بهصورت قابل اعتمادی جایگزین کلاسهای والد بشن.
- اصل جداسازی رابط (ISP) رابطها رو مختصر و مرتبط نگه میداره.
- اصل وارونگی وابستگی (DIP) تشویق میکنه به جای تکیه به پیادهسازیهای خاص، به رابطها تکیه کنی.
طراحی لاراول به طور طبیعی این اصول رو توصیه میکنه، که این باعث میشه یه فریمورک عالی برای اجرای اپلیکیشنهای قابل گسترش و نگهداری باشه.
امیدوارم این مقاله برای شما مفید بوده باشه، اگر شما هم نظر یا پیشنهادی دارید از بخش نظرات با ما در میون بزارید.
برای اطلاع از پاسخ به نظر شما می توانید ایمیل یا شماره موبایل خود را وارد نمایید. *
ایمیل و شماره موبایل شما کاملا مخفی خواهد ماند و در سایت نمایش داده نخواهد شد. *