اینترفیس ها (interfaces) از یک نظر شبیه به کلاس های انتزاعی هستند؛ هر دوی آنها دارای متدهای انتزاعی هستند که که در کلاس های فرزند باید بدنه نویسی شوند. از این نظر می توان گفت، اینترفیس ها به نظم کد کمک بزرگی می کنند چرا که کلاس های فرزند را مجبور به بدنه نویسی برای متدهای خودشان می کنند.
استفاده از اینترفیس ها معمولا در کار های تیمی نمود پیدا می کند؛ زمانی که مدیر پروژه می خواهد مطمئن شود که تک تک برنامه نویسان و توسعه دهندگان، متدهایی که به آن ها واگذار شده را خواهند نوشت.
البته می توان از اینترفیس ها جهت نظم در پروژه های شخصی نیز استفاده کرد. به عنوان مثال شما می توانید با استفاده از اینترفیس ها خود را ملزم به نوشتن متدها کنید.
برای ساخت اینترفیس ها از کلمه interface استفاده می کنیم. کلاسی که از یک اینترفیس ارث می برد با کلمه implements مشخص و تعیین می شود. به مثال زیر دقت کنید:
interface interfaceName { // متود های انتزاعی در این قسمت قرار می گیرند } class Child implements interfaceName { // این قسمت متدهای اینترفیس را تعریف می کند و ممکن است کدهای خاص خودش را نیز داشته باشد }
این مثال قالب کلی برای تعریف یک اینترفیس و فرزندش را به ما نشان می دهد.
حال در مثال زیر می خواهیم برای کلاس هایی که مسئول مدیریت ماشین ها هستند، اینترفیسی تعریف کنیم که تمام کلاس های فرزند خود را ملزوم به استفاده از متدهای ()setMethod و ()getMethod می کند:
interface Car { public function setModel($name); public function getModel(); }
اینترفیس ها مانند کلاس های انتزاعی شامل متدهای انتزاعی و ثابت ها (constants) هستند اما بر خلاف کلاس های انتزاعی فقط می توانند متدهای public داشته باشند و از طرفی نمی توانند هیچ متغیری داشته باشند.
همانطور که گفتیم کلاس هایی که از اینترفیس ارث بری دارند، موظف هستند تمام متدهایی که در اینترفیس وجود داشته است را کدنویسی کنند، و این مسئله شامل پارامتر ها هم می شود.
اگر نمی دانید پارامتر چیست به قسمت آخر مقاله زیر مراجعه کنید:
به همین دلیل کلاس miniCar در مثال زیر باید تک تک متدها را بدنه نویسی کند:
class miniCar implements Car { private $model; public function setModel($name) { $this -> model = $name; } public function getModel() { return $this -> model; } }
بله شما می توانید در یک کلاس بیش از چندین اینترفیس داشته باشید. حتما از خودتان می پرسید چرا به چنین چیزی نیاز داریم؟ اگر یادتان باشد هر کلاس فرزند فقط می توانست از یک کلاس پدر ارث بری داشته باشد. اینترفیس ها این مشکل را دور می زنند. برای نمایش چنین مثالی یک کلاس به نام Vehicle می سازیم.
interface Vehicle { public function setHasWheels($bool); public function getHasWheels(); }
حالا کلاس فرزند ما در مثال زیر می تواند از هر دو اینترفیس ارث بری داشته باشد:
class miniCar implements Car, Vehicle { private $model; private $hasWheels; public function setModel($name) { $this -> model = $name; } public function getModel() { return $this -> model; } public function setHasWheels($bool) { $this -> hasWheels = $bool; } public function getHasWheels() { return ($this -> hasWheels)? "has wheels" : "no wheels"; } }
تمامی ساختار این کدها، در مثال های دیگر، در جلسات قبل توضیح داده شده اند اما اگر با ساختار خط آخر آشنا نیستید باید بدانید این یک اپراتور ternary است. در مورد این اپراتور بیشتر بخوانید.
سوال بنیادین: چه زمانی از اینترفیس ها استفاده کنیم و چه زمانی از کلاس های انتزاعی؟ اصلا فرقشان چیست؟
پاسخ: بگذارید با یک مثال واقعی به خودمان یادآوری کنیم که اصلا فایده کلاس های انتزاعی چه بود. فرض کنید من یک سیب به شما می دهم:
<?php class Fruit { private $color; public function eat() { // جویدن } public function setColor($c) { $this->color = $c; } } class Apple extends Fruit { public function eat() { // جویدن تا هسته } } class Orange extends Fruit { public function eat() { // پوست کردن // جویدن } }
اگر بعد از اینکه یک سیب به شما دادم و شما آن را خوردید از شما بپرسم چه مزه ای داشت، به من چه می گویید؟ قاعدتا شما می گویید که مزه سیب می دهد! حالا به کد زیر نگاه کنید:
<?php $apple = new Apple(); $apple->eat(); // حالا به شما یک میوه می دهم $fruit = new Fruit(); $fruit->eat();
در کد بالا به شما یک میوه (fruit) دادم. چه مزه ای می دهد؟ طبیعتا این سوال جواب منطقی ندارد! چه میوه ای؟ میوه که یک مفهوم است و به خودی خود مزه ندارد!
بنابراین در کدها نباید اجازه داشته باشیم تا از کلاس پدر که fruit است، شیء بسازیم چرا که منطقی نیست. ما در قسمت های قبلی این مثال را با یک فروشگاه زدیم و به شما گفتیم اینجاست که از کلاس های انتزاعی (abstract) استفاده می کنیم:
<?php abstract class Fruit { private $color; abstract public function eat(){} public function setColor($c) { $this->color = $c; } } ?>
بنابراین در کلاس های انتزاعی می توانید متدها را به صورت انتزاعی تعریف کنید اما در اینترفیس ها متدها همگی انتزاعی هستند.
به علاوه، در کلاس های انتزاعی می توان متدهای کاربردی (functional) داشت اما در اینترفیس ها متدها نمی توانند بدنه داشته باشند. در واقع بدنه شان خالی است و کاری انجام نمی دهند.
منظور از متد کاربردی متدی است که واقعا کاری انجام می دهد و در قسمت بدنه کدهایی دارد. به همین ترتیب یک متغیر کاربردی یعنی یک متغیر واقعی که به طور مثال در خودش مقداری ذخیره می کند. در مثال های بالا و اینترفیس هایی که تعریف کرده ایم مشاهده می کنید که متدها در اینترفیس ها بدنه ندارند و فقط تعریف شده اند. مثال:
interface Vehicle { public function setHasWheels($bool); public function getHasWheels(); }
در مثال بالا، متدهای getHasWheels و setHasWheels خالی هستند و هیچ کاری نمی کنند تا زمانی که در کلاس فرزند تعریف شوند.
تفاوت بین interface ها و کلاس های abstract برای شما در جدول زیر به طور خلاصه تهیه شده است:
نقطه نظر / دسته بندی | اینترفیس ها | کلاس های انتزاعی |
از نظر کد | * متدهای انتزاعی
* ثابت ها (constants) |
* متدهای انتزاعی
* ثابت ها (constants) * متدهای کاربردی (functional) * متغیر های کاربردی |
از نظر access modifier | public | public
protected private و ... |
تعداد کلاس های پدر | یک کلاس می تواند بیش از یک اینترفیس داشته باشد | کلاس فرزند فقط از یک پدر ارث بری دارد |
بنابراین در دنیای واقعی و هنگام انجام پروژه های واقعی:
در ضمن اگر از جلسات قبل به خاطر داشته باشید، اگر ما با شرایط خاص (مانند استفاده از access modifier ها یا انتزاعی کردن متدها) جلوی کلاس های فرزند را نمی گرفتیم، آن ها می توانستند کدهای کلاس پدر را override کنند اما از آن جایی که اینترفیس ها نمی توانند کدهای کاربردی و فعال داشته باشند، چیزی برای override کردن وجود ندارد و هر فرزند خودش (مانند متدهای انتزاعی) بدنه کدهای خود را بنویسد.
امیدوارم از این قسمت استفاده مفید را برده باشید. در قسمت بعد به سراغ مبحث Polymorphism می رویم.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.