اصل تفکیک Interface در SOLID : معمولا برنامه نویسان تازه کار در اوایل دوران برنامه نویسی خود، دچار مشکلاتی میشوند. کدها در یک جای کار به بن بست میخورند. اوایل کار، برنامه نویس نامبرده (!) شروع به حل مسئله با روشهای خلاقانه مخصوص خود میکند! تا جایی که یک جای پروسه این روشهای خلاقانه به هم پیچ میخورند! در بهترین حالت حتی با رفع پیچ خوردگیها و تحویل پروژه، یک جای کار میلنگد: تغییر در کدها به یک کابوس شبانه شده است! برنامه نویس تازه کار با خود فکر میکند که همه راه را درست رفته. پس مشکل از کجاست؟ در این وضعیت برنامه نویسان تازه کار به دو دسته تقسیم میشوند:
مسلما این مطلب را برای دسته دوم نوشته ایم! یکی از اصول مهمی که برای دستیابی به کد تمیز مطرح است به اصول SOLID مشهور است. SOLID بر اساس این پنج اصل در طراحی کد (Code Design) تعریف میشود:
در این مطلب به معرفی اصل چهارم یعنی اصل تفکیک Interface میپردازیم.
بر اساس اصل تفکیک Interface ما نباید از Interface هایی استفاده کنیم که بیش از حد چاق هستند! رابرت مارتین (Robert Martin) مشهور به عمو باب در این باره میگوید:
کاربران نباید مجبور به استفاده از Interface هایی شوند که از آنها استفاده نمیکنند.
برای رسیدن به این هدف هر Interface باید تنها یک کار را انجام دهد. حتی در ایده آلترین حالت ممکن، بهتر است هر Interface تنها از یک متد ابسترکت (abstract) تشکیل شده باشد. در صورتی که یک Interface اصطلاحا چاق باشد (Fat Interface) کلاسهای پیاده کننده را مجبور به پیاده سازی تعداد زیادی متد میکند که قرار نیست استفاده ای از آنها بشود.
ممکن است تصور کنید که این همان اصل اول از اصول SOLID یعنی همان اصل تک وظیفگی (Single Responsibility Principle) است. در مورد کارایی حق با شماست! اما در مورد کاربرد، این دو اصل یک تفاوت کوچک دارند. اصل تک وظیفگی در مورد همه ماژولهای برنامه شامل کلاس ها، متدها و… صحبت میکند. وظیفه اصل اول ایجاد انسجام در واحدهای سازنده برنامه است. اما اصل چهارم در مورد Interfaceها و دردسرهای پیاده سازی آنها صحبت میکند.
فرض کنید یک Interface با عنوان ماشین یا Car نوشته ایم. تمام انواع کلاسهای ماشین مثل GasCar یا ElectricCar باید این Interface را پیاده سازی یا Implement کنند. Interface ماشین را به این صورت مینویسیم:
interface Car { public function getFuel(); public function shiftGear(); public function steer(); }
در مورد کلاس GasCar همه چیز به درستی پیش میرود. چون یک ماشین با سوخت گازی میتواند سوخت گیری کند، دنده عوض کند و رانده شود:
class GasCar implements Car { public function getFuel() { // getting fuel code } public function shiftGear() { // shifting gear code } public function steer() { // steering code } }
اما اگر بخواهیم یک کلاس ElectricCar داشته باشیم قضیه کمی فرق میکند. ماشین الکتریکی احتیاجی به سوخت گیری ندارد. بنابراین به متد getFuel() احتیاجی نیست. متد getFuel() باید یا مقدار null را بازگرداند، یا خطایی ارسال کند. بنابراین در این مثال اصل تفکیک Interface را نقض کرده ایم. برای حل ماجرا کافی است کمی Interface ماشینمان را لاغر کنیم! بنابراین این Interface چاق را به دو اینترفیس خوش تیپ میشکنیم:
ضمنا در مورد ماشین هایی که علاوه بر وظیفه سوخت گیری به رانده شدن هم علاقه دارند نگران نباشید! در شی گرایی میتوان به راحتی چندین Interface را توسط یک کلاس پیاده سازی کرد. بنابراین Interfaceها را دوباره به این صورت مینویسیم:
interface FuelCar { public function getFuel(); } interface RideCar { public function shiftGear(); public function steer(); }
در شی گرایی هر کلاس میتواند چندین Interface را پیاده سازی کند.
حال دو کلاس GasCar و ElectricCar به این صورت در میآیند:
class GasCar implements FuelCar,RideCar { // methods: getFuel(), shiftGear() and steer() } class ElectricCar implements RideCar { // methods: shiftGear() and steer() }
در این مطلب به معرفی اصل تفکیک Interface یا ISP پرداختیم. همانطور که دیدیم این اصل میتواند از میزان کدهای اضافی کم کند و حجم کد را کاهش دهد. بر اساس این اصل Interfaceهای چاق همه منظوره باید به Interfaceهای کوچک تک منظوره شکسته شوند. آیا شما با رعایت نکردن این اصل به مشکل بر خورده اید؟ از خواندن نظرات شما خوشحال میشویم!
. خواهشا بقیه اصل هارو هم تو برنامه داشته باشید و یه پیشنهاد امکانش هست که منابع رو در انتهای مقالات ذکر کنید که بشه به صورت مستقیم هم به منابع دسترسی داشت ( البته میدنم هم میشه سرچ کرد ولی ذکر منابع خیلی کمک بیشتری میکنه چون از صحت و کامل بودنش اطمینان کامل داریم )