تعداد بازدید: 3197

اصول SOLID در برنامه نویسی شی گرا

اصول SOLID یکی از قواعد طراحی نرم افزار به جهت افزایش خوانایی ، انعطاف و قابلیت توسعه در برنامه نویسی شئ گرا می باشد. SOLID مخفف پنج اصل می باشد که هر یک دربردارنده یک الگوی عملکرد در رویه ساختار کد نویسی است (Code Structure). 5 اصل SOLID عبارتست از :

رعایت آن ها بسته به آزادی شما در توسعه نرم افزار می تواند از بسیاری از باگ ها جلوگیری کند (خطاهایی که توسط کامپایلر شناخته نمی شوند یا خطای عملکرد ) و همچنین خوانایی برنامه را در توسعه تیمی افزایش دهد.

این اصول در برنامه نویسی شئ گرا اجرا می شود (object-oriented design) به طوری که می بینید هر یک از اصول با یکی از مفاهیم شئ گرایی مرتبط است ؛ به عبارت دیگر SOLID معماری MVC را از حالت خام (صرف جدا کردن view از منطق) در می آورد و شما را منعطف تر می کند.

`Taylor Otwell` mvc is killing you

Single responsibility

مطابق با این اصل هر یک از اجزاء منطقی نرم افزار (software entities) شامل کلاس ها توابع و … باید در قبال یک قسمت از عملکرد ارائه شده توسط نرم افزار مسئول باشد و این عملکرد باید توسط کلاس یا تابع ایزوله شده باشد(encapsulation). به زبان ساده هر کلاس یا تابع یک وظیفه داشته باشد.

در راستای این اصل رابرت مارتین می گوید تنها یک دلیل برای تغییر کلاس وجود داشته باشد( only one reason to change ) ؛ دقت کنید که متد های موجود در کلاس می تواند نوع وظیفه را در کلاس مشخص کند.

به طور مثال ما یک کنترلر برای محصول داریم. برای هر یک از وظایف این کنترلر یک کلاس باید داشته باشیم. کلاس ProductController یک کلاس برای پیاده سازی وظایف مختلف برای محصول می باشد. هر یک از این وظایف در کلاس مجزا قرار گیرد.

Class ProductController { ... }
Class AddToCart{ ... }
Class SearchProduct{ ... }
Class ControllerLogic{ ... }

مطابق رویه کد بالا هر کلاس به شامل methods و Properties ها در راستای اجرای یک هدف پیش می روند.(Methods,Properties ⇒ Same Goal)

Open–closed

ساختار تمامی اجزای یک نرم افزار (software entities) باید طوری پیاده سازی گردند که باز برای توسعه باز باشند و برای تغییر بسته باشند ؛ به گونه ای که رفتار ماژول های نرم افزار باید به گونه ای باشد که توسعه نرم افزار بدون تغییر اساسی در سورس اصلی انجام پذیرد.

should be open for extension, but closed for modification

لازمه اجرای این اصل جداسازی Logic ها از هم و عدم تکرار Logic و استفاده از سیستم Routing در کلاس ها و متد ها می باشد. مثلا یک عملکرد به ازای نوع درخواست می تواند متفاوت باشد. اگر یک درخواست جدید به لیست درخواست ها اضافه شد امکانات جدید نرم افزار بدون تغییر کد های قبل پیاده سازی گردد.

public function bpp_action() {
	$map = array(
		array(
			'key' => 'rngbpp_increase_price',
			'method' => array($this->action, 'modify_price'),
			'params' => array($this->logic, "increase", $product_ids, $percent, $value)
		),
		array(
			'key' => 'rngbpp_decrease_price',
			'method' => array($this->action, 'modify_price'),
			'params' => array($this->logic, "decrease", $product_ids, $percent, $value)
		),
	);
	foreach ($map as $callback):
		if (isset($_POST[$callback['key']])):
			call_user_func_array($callback['method'], $callback['params']);
			break;
		endif;
	endforeach;
}

مثلا در متد بالا هر یک از کلید های ‘key’ در آرایه map برابر با یک امکان در این نرم افزار می باشد که هر کدام به یک متد در یک کلاس Action هدایت می شود. در صورت اضافه شدن یک امکان جدید به نرم افزار ما یک کلید جدید به آرایه map اضافه می کنیم و صرفا یک عملکرد جدید بدون تغییر در کد های قبل اضافه می کنیم. کلاس ها قابل توسعه بدون تغییر در کدهای قبل کلاس .

این توسعه نیز می تواند با استفاده از Interface اتفاق بیفتد . به طور مثال CustomerInterface را داشته باشیم که یک سری قوانین در رابطه با مشتریان بدهد . پس از آن نیاز باشد که کلاس های مجزا برای یک سری مشتریان خاص تر (در دسته های مختلف) ساخته شود مثلا SpecialCustomer implements CustomerInterface (polymorphism).

Liskov Substitution

این اصل بدین معنی است که کلاس فرزند نباید عملکرد کلاس والد خود را مختل کند ؛ اصول و عملکرد متد های override شده در کلاس های فرزند باید گسترش یافته (قوی تر) متد در کلاس والد باشد.

class Banner_Widget extends WP_Widget {

    public function __construct() {
        $widget_options = array(
            "classname" => "rng_benner",
            "description" => __("widget description")
        );
        parent::__construct("rng_banner", __("widget title"), $widget_options);
    }

}

در کد بالا با استفاده از قطعه کد parent::__construct امکانات متد سازنده والد را کلاس فرزند اضافه کردیم و متد بزرگتر شده است.

Interface Segregation

این مفهوم به معنی تفکیک Interface ها بر اساس منطق پیاده سازی آن ها می باشد.یعنی یک کلاس نباید پس از پیاده سازی (Implement) از یک Interface مجبور باشه متد هایی رو پیاده سازی کنه که به اون ها نیازی نداشته باشه. این موضوع نیازمند رعایت نکات زیر است :

  • Interface ها رو کوچک تر و بر اساس منطق بسازید. مثلا به جای یک interface بزرگ چند interface کوچک داشته باشید.
  • کلاس Interface رو برای پیاده سازی به درستی انتخاب کنید.(مفاهیم کلاس ها با هم بخواند).
interface PostInterface{
    public function publish();
    public function setPrice();
    public function setWeight();
    public function addContent();
}

class Portfolio implements PostInterface{
    public function publish(){..}
    public function setPrice(){..}
    public function setWeight(){..}
    public function addContent(){..}
    public function DateStart(){..}
}

در کد بالا Interface با نام Post خیلی بزرگ خواهد بود اگر بخواهد تمامی امکانات انواع پست را پیاده سازی کند. همچنین انواع post type های گوناگون نظیر Product و Portfolio نیز باید یک سری متد های غیر ضروری را که برای سایر پست تایپ ها تعبیه شده را باید پیاده سازی کنند.

A client should not be forced to use interfaces that it doesn’t need.

مثلا در بالا ما در کلاس Portfolio متد های setPrice و setWeight را نیازی نداریم و بسته به PostInterface پیاده سازی کردیم . کد را به شکل زیر اصلاح می کنیم :

interface PostInterface{
    public function publish();
    public function addContent();
}

interface ProductInterface{
    public function setPrice();
    public function setWeight();
}

interface PortfolioInterface{
    public function DateStart(){..}
}

class Portfolio implements PortfolioInterface,PostInterface{
    public function publish(){..}
    public function addContent(){..}
    public function DateStart(){..}
}

Dependency Inversion

وارونگی وابستگی ها یا dependency inversion یعنی عدم وابستگی به صورت وارونه در کلاس ها ؛ در دنیای واقعی وقتی کسی به شما می گوید به مشهد برو شما با استفاده از یکی از ابزار های در دسترس ( تاکسی ، اتوبوس ، هواپیما) به آنجا می روید رفتن به مشهد کد سطح بالا و استفاده از ابزار ها کد سطح پایین می باشد که شما فارغ از ابزار این تصمیم را می گیرید.

کدهای سطح بالا High-level Code یا ( کدهای سرپرست ) کدهایی هستند که با نگاه بالا به پایین و فارغ از Low-level Detail کار می کنند. Low-level Detail کدهایی هستند که کار آخر را انجام می دهند ( کد های کارگر ).

وابستگی میان کلاس ها را Dependency می نامیم . مثلا یک کلاس به نام شمارنده میوه یک کلاس از جنس میوه را می گیرد و تعداد آن را بر میگرداند.

class CountApples
{
    private $apple;
    public function __contsruct($apple)
    {
        $this->apple = $apple;
    }

    public function howMany()
    {
        return count($this->apple->howMany());
    }
}

در کد بالا کلاس CoutnApples یک کد سطح بالا است و به کد سطح پایین یعنی Apple وابسته می باشد. باید نگاه ساختاری ما در کد سطح بالا کلی تر و فارغ از کد سطح پایین یعنی Apple باشد. این کار را با استفاده از Interface انجام می دهیم. این کار باعث تسهیل در روند تست نویسی ما نیز می شود.

class CountFruit
{
    private $fruit;
    public function __contsruct($fruit)
    {
        $this->fruit = $fruit;
    }

    public function howMany()
    {
        return count($this->fruit->howMany());
    }
}

/** Create our generic fruit interface **/

interface Fruit
{
    public function howMany();
}

/** Create our clients **/

class Apples implements Fruit
{
    public function howMany()
    {
        return 14;
    }
}

class Bananas implements Fruit
{
    public function howMany()
    {
        return 6;
    }
}

این مفاهیم (High-level Code , Low-level Detail)به صورت نسبی می باشند. ممکن است یک کلاس نسبت به یک کلاس High level می باشد و نسبت به کدی دیگر Low-level باشد.

اگر وابستگی قبل از اجرای کد انجام بپذیرد Compile Time Dependency می باشد ولی اگر بعد از اجرا این وابستگی مشخص گردد ( برا اساس درخواست کاربر) به آن Run Time Dependency می گوییم.

مطالب مشابه

ftp-protocol-in-php

کار با پروتکل FTP در PHP

یکی دیگر قوانین حاکم بر دنیای وب ( از پروتکل های اینترنت لایه application ) پروتکل ftp است که با استفاده از آن می...

email handling in php

ارسال و دریافت ایمیل در php

قوانین حکم فرما بر دنیای وب را پروتکل می نامیم. پروتکل http که در سرور ها برای ایجاد پاسخ به درخواست ها در برخی...

معماری های MVC/HMVC

معماری MVC یک قالب برای پیاده سازی رفتار نرم افزار می باشد که بر پایه Model و Controller و View می باشد. controller...

اشتراک گذاری :

مدیر وب سایت گنوتک . برنامه نویسی رو با زبان C در هفده سالگی شروع کردم . در حال حاضر به برنامه نویسی php برپایه معماری MVC , HMVC و همچنین سیستم مدیریت محتوای WordPress و فریم ورک محبوب لاراول علاقه مند هستم و دوست دارم اطلاعاتم رو با شما به اشتراک بگذارم.

یک دیدگاه برای اصول SOLID در برنامه نویسی شی گرا

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *