این اصل حاکی از آن است که یک کلاسی که از یک اینترفیس ایمپلیمنت میکند هرگز نباید مجبور باشد تا کلیهٔ بخشهایش که حتی نیازی به آنها ندارد را پیادهسازی کند. به عبارتی، داشتن چندین و چند اینترفیس کوچک و در عین حال تخصصی به مراتب بهتر از داشتن یک اینترفیس کلی و همهمنظوره است.
برای درک بهتر Interface Segregation Principle یا به اختصار ISP، پروژهای به صورت زیر را در نظر میگیریم:
interface-segregation-principle/
├── Codable.php
├── Developer.php
├── EmployeeInterface.php
├── Testable.php
└── Tester.php
لازم به یادآوری است که برای شلوغ نشدن سورسکدهای مورد استفاده در این آموزش، از نوشتن کلیهٔ تگهای آغازین php؟>
خودداری کردهایم. به منظور روشن شدن کاربرد ISP، ساختار پروژهٔ زیر را مد نظر قرار میدهیم:
ابتدا پوشهای به نام 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) میباشند زیرا کلاسهایی که از آنها ایمپلیمنت میشوند بیش از یک تَسک را باید انجام دهند.