با سلام، در جلسات قبل مبحث کلاس ها و متد های انتزاعی را پیش بردیم و در این قسمت با مبحثی بسیار مشابه آنها یعنی مبحث اینترفیس ها روبرو می شویم.
اینترفیس ها (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 می رویم.
در پناه حق
دیدگاههای شما (3 دیدگاه)
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.