۱۴۰۰/۰۲/۲۹

Liskov Substitution Principal  یا LSP در php

Liskov Substitution Principal in Php ۱۳۹۸/۰۶/۲۲

Liskov Substitution Principal  یا LSP یکی از اصول SOLID است.که برای اولین بار توسط Barbara Liskov  در سال 1987 مطرح شد بطور کلی یعنی هیچ کلاس فرزند نباید رفتار کلاس والد را تغییر دهد.

در یک نرم افزار اگر M زیرمجموه S باشد.اگر اشیاع از نوع S با اشیا از نوع M جایگزین شوند.بدون اینکه هیچ کدام از خصوصیات نرم افزار را تغییر دهند.یا به عبارت دیگر ، هر متدی که از آبجکت فراخوانی میشود، باید در صورت جایگزینی آن اشیاء با نمونه های زیرمجموعه ، همچنان به کار خود ادامه دهد.

زیرمجموعه چیست؟

در بیشتر زبانهای شی گرا یک زیرگروه می تواند یک کلاس باشد که از  یک کلاس دیگرمشتق یا extend شده باشد ، یا یک کلاس که از یک اینترفیس implement شده باشد .

 به یک مثال در PHP نگاه کنیم.

interface Animal {} 
class Cat implements Animal {} 
class MaineCoon extends Cat {} 

// A class implementing an interface is considered to be a subclass of said interface. 
 is_subclass_of(Cat::class, Animal::class); // bool(true) 

// A class extending another class is a subclass of said parent class.
  is_subclass_of(MaineCoon::class, Cat::class); // bool(true)
 
 // By extension, the child class is also considered to be a subclass of the interfaces
 // implemented by its parent class. 
  is_subclass_of(MaineCoon::class, Animal::class); // bool(true)

 

 

PHP-Liskov-Substitution-Principal

برای نشان دادن این موضوع به طور کامل ، با یک مثال کلاسیک روبرو خواهیم شد زیرا به راحتی قابل درک است.

class Rectangle {

    private $topLeft;
    private $width;
    private $height;

    public function setHeight($height) {
        $this->height = $height;
    }

    public function getHeight() {
        return $this->height;
    }
    public function setWidth($width) {
       $this->width = $width;
    }
    public function getWidth() {
        return $this->width;
    }
}

برای پیاده سازی این روش از محاسبه محیط  ، یک مستطیل شروع می کنیم. این فقط یک کلاس ساده است که عرض و ارتفاع یک مستطیل را دریافت میکند. تصور کنید که برنامه ما در حال کار است و چندین کلاس از ان ارث بری کرده اند . اکنون آنها به یک ویژگی جدید احتیاج دارند. آنها باید بتوانند محیط مربع ها را هم محاصبه کنند.

در زندگی واقعی ، در هندسه ، یک مربع شکل خاصی از مستطیل است. بنابراین ما می توانیم سعی کنیم یک کلاس Square را اجرا کنیم که یک کلاس مستطیل را گسترش دهد. اغلب گفته می شود که کلاس فرزند مشتق شده  کلاس والدین است و این عبارت حداقل با نگاه اول مطابقت دارد با LSP.

class Square extends Rectangle {

    public function setHeight($value) {
        $this->width = $value;
        $this->height = $value;
    }
    public function setWidth($value) {
        $this->width = $value;
        $this->height = $value;
     }

در واقع یک مربع  مستطیلی است  با عرض و ارتفاع مساوی و مانند کد بالا می توانیم یک اجرای پیجیده محیط را محاسبه کنیم . ما می توانیم برای تنظیم ارتفاع و عرض ، هر دو تنظیم را overwrite  کنیم. اما این امر چگونه می تواند بر کد کلاس مشتری تأثیر بگذارد؟

class Client {

    function areaVerifier(Rectangle $r) {
        $r->setWidth(5);
        $r->setHeight(4);
        if($r->area() != 20) {
            throw new Exception('Bad area!');
        }
        return true;
    }
}

این امکان پذیر است که یک کلاس مشتری بتواند در صورت اشتباه در منطق محاصبه یک استثنا را پرتاب کند.

function area() {
    return $this->width * $this->height;
}

البته برای محاصبه محیط یک متد به کلاس Rectangle اضافه میکنیم.

class LspTest extends PHPUnit_Framework_TestCase {
    function testRectangleArea() {
        $r = new Rectangle();
        $c = new Client();
        $this->assertTrue($c->areaVerifier($r));
    }
}

در کد بالا یک کلاس تست ساده با ارسال یک rectangle object خالی به متد areaVerifier ایجاد کردیم.اگر کلاس Square به درستی تعریف شده باشد.با ارسال آن به متد areaVerifier از کلاس Client نباید عملکرد آن را خراب کند.

function testSquareArea() {
    $r = new Square();
    $c = new Client();
    $this->assertTrue($c->areaVerifier($r));
}

با انجام تست بالا یک استثنا برای ما پرتاب میشود.

PHPUnit 3.7.28 by Sebastian Bergmann.
Exception : Bad area!
#0 /paht/: /.../.../LspTest.php(18): Client->areaVerifier(Object(Square))
#1 [internal function]: LspTest->testSquareArea()

بنابراین ، کلاس Square یک مستطیل نیست. قوانین هندسه را می شکند.و اصل جایگزینی لیسکوف را نقض می کند.

یک قاعده کلی که برای رعایت اصول LSP در PHP باید رعایت شود . این است ک نوع مقدار برگشتی هر متد باید هم نوع با مقدار برگشتی کلاس پدر باشد.بعنوان مثال اگر مقدار برگشتی متد search از کلاس T نمونه ای از Illuminate\\Support\\Collection باشد آنگاه هر متد search از نوع S باید نوع برگشتی آن از نوع  Illuminate\\Support\\Collection باشد.

چهار قانونی که در روش LSP باید رعایت شود به شرح زیر است .

1-متد ها باید پارامترهای یکسان داشته باشند.

2-هر متد از کلاس مشتق شده نباید استثناهای بیشتر از کلاس پدر در مقدار برگشتی داشته باشند.مانند  پرتاب یک استثنا throwing an Exception

3-نوع مقدار برگشتی متدهای مشتق شده از کلاس فرزند باید با نوع مقدار برگشتی کلاس پدر یکسان باشد

4-اگر در کلاس متدی ایجاد شده که یک استثنا مثل FileNotFoundException را برگرداند.در همان وضعیت کلاس مشتق شده باید مقدار برگشتی  FileNotFoundException را برگرداند.

از آنجا که در php نمی توان نوع مقدار برگشتی متد را صریحا مشخص کرد.ما باید مطمئن باشیم که مقدار های برگشتی کلاس فرزند هم نوع با والد با interface خود باشد.

بطور مثال 

interface LessonRepositoryInterface
{
    /**
     * Gets all lessons.
     *
     * @return array
     */
     public function getAll();
}
class FilesystemLessonRepository implements LessonRepositoryInterface
{
    public function getAll()
    {
        // Fetch the lessons from the filesystem
        return $files;
    }
}
class DatabaseLessonRepository implements LessonRepositoryInterface
{
    public function getAll()
    {
        return Lesson::all()->toArray();
    }
}

همانطور که در کد بالا میبینید.هر دو کلاس ها مشتق شده اند از LessonRepositoryInterface با متد getAll.بطور کلی باید مطمئن باشیم که مدل Eloquent مقدار بازگشتی از نوع آرایه دارد.

 Liskov Substitution Principle بدین معنی است که کلاس های فرزند که از کلاس والد مشتق میشوند باید یکسری قوانین را رعایت کنند.مثل داشتن متد ها و پارامتر های یکسان.مقادیر برگشتی باید با نوع مقدار برگشتی متدهای کلاس والد یکسان باشد.و یا اگر متدی در کلاس والد استثنایی پرتاب میکند در همان شرایط باید کلاس فرزند همان استثنا را پرتاب کند.

PHP-Liskov-Substitution-Principal


رای :

Liskov Substitution Principal

php

SOLID

LSP

ارسال نظر
Copyright © All right reserved.