ما زمانی از کلاس های Abstract یا انتزاعی استفاده می کنیم که بخواهیم برنامه نویس را ملزم به نوشتن متد خاصی کنیم. اما فقط می توانیم از همان نام متد مطمئن شویم و نه جزئیات کد تابع.
برای مثال، مربع، مستطیل، هشت ضلعی و… شاید شبیه هم باشند ولی همه آنها اشکال دو بعدی هستند و بنابراین همه دارای صفات محیط و مساحت اند.
بنابراین منطقی است که آنها را در یک کلاس مادر (parent) قرار بدیم. ما دو خصوصیت (attribute) مساحت و محیط داریم پس باید متدی برای محاسبه آن اضافه کنیم (که ممکنه مشکل ساز بشه چون هر شکل روش محاسبه متفاتی دارد)
در این موارد، زمانی که باید کلاس های فرزند را به متدهای خاصی که از کلاس والد به ارث می برند، متعهد کنیم اما نمی توانیم به استفاده از متد با کد خاص مجبور کنیم از کلاس های Abstract استفاده می کنیم.
کلاس انتزاعی حداقل یک متد abstract دارد. متدهای abstract فقط می توانند نام و آرگومان بگیرند و هیچ کدی در بدنه تابع وجود ندارد.
ما نمی توانیم از این کلاس ها آبجکت بسازیم. به جای آن فقط نیاز است کلاس فرزند از کلاس abstract ارث بری کند و بدنه متد ها را داخل کلاس فرزند بنویسم و بعد از کلاس فرزند می توانیم آبجکت بسازیم.
تعریف کلاس و متدهای Abstract
به منظور تعریف یک کلاس انتزاعی، کافیست کلیدواژه abstract
را به همراه class
بکار ببریم
مثال زیر را ببینید:
1 |
abstract class Car { } |
ما متدهای های abstract را هم با کلمه کلیدی abstract
داخل کلاس مشخص می کنیم.
داخل متدهای کلاس هیچ کدی قرار نمیدیم و فقط نام و پارامترهای ورودی را مشخص می کنیم.
در این مثال، ما متد abstract
عمومی calcNumMilesOnFullTank()
را مشخص کردیم و از آن داخل کلاس فرزند بهره می بریم.
این متد مسافتی را که ماشین با باک پر می تواند طی کند را به مایل برگشت می دهد
1 2 3 4 |
// Abstract classes are declared with the abstract keyword, and contain abstract methods. abstract class Car { abstract public function calcNumMilesOnFullTank(); } |
توجه کنید که همینکه یک متد بصورت abstract بود باید کلاس هم بصورت abstract باشد.
می توانیم از متدهای معمولی داخل کلاس abstract استفاده کنیم؟
بله، حتی خصوصیات (properties) ها هم می توانید abstract باشند یا نباشند.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
abstract class Car { // Abstract classes can have properties protected $tankVolume; // Abstract classes can have non abstract methods public function setTankVolume($volume) { $this -> tankVolume = $volume; } // Abstract method abstract public function calcNumMilesOnFullTank(); } |
حالا به مثال قبلی پراپرتی خصوصی $tankVolume
و متد عمومی setTankVolume()
را اضافه می کنیم :
ساخت کلاس فرزند از کلاس abstract
از آنجایی که نمی توانیم از کلاس های abstract آبجکت بسازیم, نیاز است که کلاس فرزندی ایجاد کنیم که از کدهای کلاس انتزاعی ارث بری می کند.
کلاس های فرزند با کلمه کلیدی extends
از کلاس های abstract ارث بری می کنند (همانند دیگر کلاس ها)
فقط یک تفاوت وجود دارد اینکه کلاس های فرزند ارث بری شده از کلاس های abstract باید بدنه متدهای abstract را در خود اضافه کنند.
یک کلاس فرزند به نام Honda ساختیم و بدنه متد calcNumMilesOnFullTank() را داخل آن مشخص کردیم:
1 2 3 4 5 6 7 8 9 |
class Honda extends Car { // Since we inherited abstract method, we need to define it in the child class, // by adding code to the method's body. public function calcNumMilesOnFullTank() { $miles = $this -> tankVolume*30; return $miles; } } |
ما می توانیم کلاس فرزند دیگری به نام Toyota
از کلاس Car
بسازیم تا محاسبه جداگانه ای برای متد calcNumMilesOnFullTank()
قرار بدیم چون هر ماشین مسافت مشخصی بر اساس باک پر می تواند طی کند.
همچنین متد دیگری به خود کلاس فرزند به اسم getColor()
اضافه کردیم که رشته “black” برگشت می دهد
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Toyota extends Car { // Since we inherited abstract method, we need to define it in the child class, // by adding code to the method's body. public function calcNumMilesOnFullTank() { return $miles = $this -> tankVolume*33; } public function getColor() { return "black"; } } |
حالا آبجکت جدید به اسم $toyota1
می سازیم که حجم ۱۰ را براش مشخص و رنگ ماشین را هم در خروجی چاپ کردیم
1 2 3 4 |
$toyota1 = new Toyota(); $toyota1 -> setTankVolume(10); echo $toyota1 -> calcNumMilesOnFullTank();//330 echo $toyota1 -> getColor();//black |
جمع بندی
در این بخش از آموزش شی گرایی در PHP، مفهوم کلاس و متدهای انتزاعی را یاد گرفتید که برنامه نویس را متعهد می کند از همان متدهای هم نامی که ساختیم استفاده کند تا بتواند کد بدنه آن را بر اساس کلاس فرزند خود بنویسد.
در بخش بعدی مفهوم انتزاعی را دوباره مرور میکنیم ولی اینبار از interface
استفاده می کنیم.