درآمدی بر قانون Interface Segregation


این اصل حاکی از آن است که یک کلاسی که از یک اینترفیس ایمپلیمنت می‌کند هرگز نباید مجبور باشد تا کلیهٔ بخش‌هایش که حتی نیازی به آن‌ها ندارد را پیاده‌سازی کند. به عبارتی،‌ داشتن چندین و چند اینترفیس کوچک و در عین حال تخصصی به مراتب بهتر از داشتن یک اینترفیس کلی و همه‌منظوره است.

برای درک بهتر Interface Segregation Principle یا به اختصار ISP، پروژه‌ای به صورت زیر را در نظر می‌گیریم:

interface-segregation-principle/
├── Codable.php
├── Developer.php
├── EmployeeInterface.php
├── Testable.php
└── Tester.php

لازم به یادآوری است که برای شلوغ نشدن سورس‌کدهای مورد استفاده در این آموزش، از نوشتن کلیهٔ تگ‌های آغازین php؟> خودداری کرده‌ایم. به منظور روشن شدن کاربرد SRP، ساختار پروژهٔ زیر را مد نظر قرار می‌دهیم:

ابتدا پوشه‌ای به نام interface-segregation-principle درست کرده،‌ سپس در فایلی تحت عنوان EmployeeInterface.php اینترفیسی تحت عنوان EmployeeInterface به صورت زیر می‌نویسیم:

interface EmployeeInterface
{
    public function code();
    public function testInLocalhost();
    public function testUserExperience();
    public function talkToClients();
}

حال در فایلی به اسم Developer.php کلاسی تحت عنوان Developer می‌نویسیم که از اینترفیس فوق ایمپلیمنت می‌شود:

require_once 'EmployeeInterface.php';
class Developer implements EmployeeInterface
{
    public function code()
    {
        return true;
    }

    public function testInLocalhost()
    {
        return true;
    }

    public function testUserExperience()
    {

    }

    public function talkToClients()
    {

    }
}

در حقیقت، یک دولوپر صرافاً با فانکشن‌های ()code و ()testInLocalhost سروکار دارد و اصلاً نیازی به فانکشن‌های ()testUserExperience و ()talkToClients ندارد اما از آنجا که قوانین زبان پی‌اچ‌پی ما را ملزم می‌کند تا تمامی فانکشن‌های تعریف‌شده داخل اینترفیس را داخلی کلاسی که از آن ایمپلیمنت می‌شود استفاده کنیم، مجبوریم این دو فانکشن را با بدنهٔ خالی داخل کلاس خود درج کنیم! برای تکمیل این پروژه، فایلی تحت عنوان Tester.php ساخته و کلاسی با نام Tester داخل آن تعریف می‌کنیم:

require_once 'EmployeeInterface.php';
class Tester implements EmployeeInterface
{
    public function code()
    {

    }

    public function testInLocalhost()
    {

    }

    public function testUserExperience()
    {
        return true;
    }

    public function talkToClients()
    {
        return fasle;
    }
}

می‌بینیم که بر خلاف کلاس Developer ما در این کلاس صرفاً نیاز به متد ()testUserExperience داریم و این در حالی است که متد ()talkToClients به دردِ هیچ‌کدام از این دو کلاس نمی‌خورد و در صورتی که کلاس مرتبط با PR (روابط عمومی) داشته باشیم، می‌توانیم از آن استفاده نماییم.

با این تفاسیر، اینجا است که قانون ISP به کمک ما می‌آید بدین صورت که دولوپر را موظف می‌سازد تا اینترفیس‌های کوچک و تخصصی بنویسید به طوری که خواهیم داشت:

interface Codeable
{
    public function code();
    public function testInLocalhost();
}

فایلی تحت عنوان Codable.php ساخته و اینترفیس فوق را داخل آن می‌نویسیم به طوری که فقط و فقط مختص دولوپرها است به طوری که کلاس Developer را به صورت زیر می‌توانیم ریفتکور کنیم:

require_once 'Codeable.php';
class Developer implements Codeable
{
    public function code()
    {
        return true;
    }

    public function testInLocalhost()
    {
        return true;
    }
}

و به همین منوال فایل دیگری تحت عنوان Testable.php ساخته و اینترفیسی تحت عنوان Testable داخل آن می‌نویسیم که صرفاً برای تِستِر‌های نرم‌افزار مناسب خواهد بود:

interface Testable
{
    public function testUserExperience();
}

در ادامه کلاس Tester را به صورت زیر ریفکتور خواهیم کرد:

require_once 'Testable.php';
class Tester implements Testable
{
    public function testUserExperience()
    {
        return true;
    }
}

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

require_once 'Codeable.php';
require_once 'Testable.php';
class Developer implements Codeable, Testable
{
    public function code()
    {
        return true;
    }

    public function testInLocalhost()
    {
        return true;
    }

    public function testUserExperience()
    {
        return true;
    }
}

می‌بینیم که از هر دو اینترفیس‌ Codeable و Testable ایمپلیمنت کرده و فانکشن ()testUserExperience را هم به کلاس خود افزوده‌ایم.

روی هم رفته، ISP این اطمینان را حاصل می‌کند که کلاس‌های‌مان صرفاً حاوی فانکشن‌هایی باشند که به آن‌ها نیاز دارند و از نوشتن اینترفیس‌هایی که کلی و جهان‌شمول هستند جلوگیری می‌کند. در واقع، اینترفیسی‌های کلی ناقض قانون اول (Single Responsibility Principle) می‌باشند زیرا کلاس‌هایی که از آن‌ها ایمپلیمنت می‌شوند بیش از یک تَسک را باید انجام دهند.

دانلود فایل‌های تمرین

لیست نظرات
کاربر میهمان
دیدگاه شما چیست؟
کاربر میهمان
abdalily932320
abdalily932320
۱۳۹۸/۰۶/۲۹
توی این مثال آیا قانون OCP نقض نشده