الواجهة مقابل الـ Abstract Class
جزء من قسم Object Oriented Programming في رحلة PHP على Coddy — الدرس 30 من 91.
الآن بعد أن تعلمت كلًا من الواجهات (interfaces) والفئات المجردة (abstract classes)، دعنا نوضح متى نستخدم كلًا منهما. فبينما قد يبدوان متشابهين، إلا أنهما يخدمان أغراضًا مختلفة ولهما قدرات متميزة.
| الميزة | الواجهة (Interface) | الفئة المجردة (Abstract Class) |
|---|---|---|
| الدوال (Methods) | تواقيع الدوال فقط | كلا النوعين من الدوال (المجردة والملموسة) |
| الخصائص (Properties) | الثوابت فقط | يمكن أن تحتوي على خصائص |
| الوراثة المتعددة | يمكن للفئة تنفيذ واجهات متعددة | يمكن للفئة وراثة فئة واحدة فقط |
| المنشئ (Constructor) | غير مسموح به | يمكن أن تحتوي على منشئ |
استخدم interface عندما تريد تعريف عقد يمكن للأصناف غير المرتبطة الوفاء به. على سبيل المثال، قد يقوم كل من Printer و Logger بتنفيذ واجهة Writable، على الرغم من أنهما لا يشتركان في أي سلف مشترك.
استخدم فئة مجردة (abstract class) عندما يكون لديك فئات ذات صلة تشترك في كود برمجي مشترك. إذا كانت فئتا Dog و Cat تحتاجان إلى نفس تنفيذ الدالة eat()، فإن فئة Animal مجردة (abstract) تتيح لك كتابة هذا الكود مرة واحدة.
يمكنك أيضاً الجمع بين كلا النهجين. حيث يمكن لفئة (class) أن ترث من فئة مجردة (abstract class) مع تنفيذ واجهات (interfaces) متعددة في آن واحد:
<?php
abstract class Animal {
protected $name;
public function eat() {
return $this->name . " is eating";
}
}
interface Swimmable {
public function swim();
}
class Duck extends Animal implements Swimmable {
public function __construct($name) {
$this->name = $name;
}
public function swim() {
return $this->name . " is swimming";
}
}
نقطة رئيسية: اختر الواجهات (interfaces) لتحديد القدرات عبر الفئات (classes) غير المرتبطة. اختر الفئات المجردة (abstract classes) عندما تحتاج إلى مشاركة الكود بين الفئات ذات الصلة.
التحدي
سهللنقم ببناء نظام مركبات يوضح متى يجب استخدام فئة مجردة (abstract class) مقابل واجهة (interface) — وكيفية الجمع بين كلا النهجين بفعالية.
ستقوم بإنشاء نظام تشترك فيه المركبات في خصائص عامة من خلال الوراثة، ولكن يمكنها أيضاً اكتساب قدرات إضافية من خلال الواجهات. هذا يحاكي قرارات التصميم في العالم الحقيقي: السيارة "هي" مركبة (وراثة)، ولكن لديها أيضاً "القدرة" على أن تكون قابلة للتزود بالوقود (واجهة).
قم بتنظيم الكود الخاص بك عبر أربعة ملفات:
Refuelable.php— قم بتعريف واجهةRefuelableمع توقيع طريقة واحدة:refuel($amount). يمكن تطبيق هذه القدرة على أي فئة تحتاج إلى التزود بالوقود، بغض النظر عن تسلسل الوراثة الخاص بها.Vehicle.php— قم بتعريف فئة مجردةVehicleتوفر وظائف مشتركة لجميع المركبات. يجب أن تحتوي على خاصية محمية$brandوخاصية محمية$fuelLevel(تبدأ بـ 0). يقبل المنشئ (constructor) اسم العلامة التجارية. قم بتضمين طريقة ملموسةgetBrand()تعيد العلامة التجارية، وطريقة ملموسةgetFuelLevel()تعيد مستوى الوقود الحالي، وطريقة مجردةdrive()يجب على الفئات التابعة تنفيذها.Car.php— قم بإنشاء فئةCarترث منVehicleوتنفذRefuelable. قم بتضمين كلا الملفين المطلوبين في الأعلى. يقبل المنشئ العلامة التجارية ويمررها إلى منشئ الفئة الأب. قم بتنفيذdrive()لتعيد"[brand] car is driving". قم بتنفيذrefuel($amount)لإضافة الكمية إلى مستوى الوقود وإعادة"[brand] refueled to [fuelLevel] liters".main.php— قم بتضمين ملف Car. ستتلقى مدخلين: اسم العلامة التجارية وكمية الوقود (قم بتحويلها إلى عدد صحيح). قم بإنشاءCarبالعلامة التجارية. اطبع نتيجةdrive()في السطر الأول، ثم اطبع نتيجةrefuel()مع كمية الوقود في السطر الثاني.
يوضح هذا التحدي التمييز الرئيسي: الفئة المجردة Vehicle تشارك الكود وتؤسس علاقة "is-a" (هي نوع من)، بينما تضيف واجهة Refuelable قدرة يمكن تطبيقها على فئات أخرى غير مرتبطة (مثل المولد أو القارب) دون مطالبتها بأن تكون مركبات.
ورقة مرجعية
تخدم الواجهات (Interfaces) والفئات المجردة (Abstract classes) أغراضاً مختلفة:
| الميزة | الواجهة (Interface) | الفئة المجردة (Abstract Class) |
|---|---|---|
| الأساليب (Methods) | تواقيع الأساليب فقط | كل من الأساليب المجردة والملموسة |
| الخصائص (Properties) | الثوابت فقط | يمكن أن تحتوي على خصائص |
| الوراثة المتعددة | يمكن للفئة تنفيذ العديد منها | يمكن للفئة توسيع واحدة فقط |
| المنشئ (Constructor) | غير مسموح به | يمكن أن تحتوي على منشئ |
استخدم الواجهة (interface) لتحديد عقد للفئات غير المرتبطة. استخدم الفئة المجردة (abstract class) لمشاركة الكود المشترك بين الفئات المرتبطة.
يمكن للفئة توسيع فئة مجردة مع تنفيذ واجهات متعددة في نفس الوقت:
<?php
abstract class Animal {
protected $name;
public function eat() {
return $this->name . " is eating";
}
}
interface Swimmable {
public function swim();
}
class Duck extends Animal implements Swimmable {
public function __construct($name) {
$this->name = $name;
}
public function swim() {
return $this->name . " is swimming";
}
}
جرّب بنفسك
<?php
require_once 'Car.php';
// قراءة المدخلات
$brand = trim(fgets(STDIN));
$fuelAmount = intval(trim(fgets(STDIN)));
// TODO: إنشاء كائن Car مع العلامة التجارية (brand)
// TODO: طباعة نتيجة drive() في السطر الأول
// TODO: طباعة نتيجة refuel() مع كمية الوقود في السطر الثاني
?>يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات OOP
الملفات الخارجيةمقدمة في OOPClasses مقابل Objectsالكلمة المفتاحية $thisالـ Methodsالـ Propertiesالمنشئ (__construct)الهادم (__destruct)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسيةالكلمة المفتاحية parent::إعادة تعريف الدوال (Method Overriding)الكلمة المفتاحية finalالأصناف المجردة (Abstract Classes)مراجعة - هيكلية الموظفين7التغليف (Encapsulation)
العام، المحمي، الخاص (Public, Protected, Private)نظرة متعمقة على معدلات الوصولدوال Getters و Settersإخفاء المعلوماتميزة Constructor Promotion (8.0)مراجعة - نظام سجلات الطلاب10مفاهيم البرمجة كائنية التوجه المتقدمة
التركيب مقابل الوراثةحقن التبعيةالأصناف المجهولةالتعدادات (PHP 8.1)الألياف (PHP 8.1)تعمق في استنساخ الكائناتالمولدات والمكررات13أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المستودع2مساحات الأسماء والتحميل التلقائي
مقدمة إلى مساحات الأسماءالكلمة المفتاحية useمعيار التحميل التلقائي PSR-4أداة التحميل التلقائي Composerملخص - مشروع منظم5الواجهات والعقود
مقدمة إلى الواجهاتتنفيذ الواجهاتتنفيذ واجهات متعددةالواجهة مقابل الـ Abstract Classالـ Type Hinting مع الواجهاتملخص - حاسبة الأشكال8الميثودات السحرية (Magic Methods)
مقدمة في الميثودات السحرية__toString و __debugInfo__get, __set, __isset, __unset__call و __callStatic__clone واستنساخ الكائنات__serialize و __unserializeمراجعة - Custom Collection3خصائص الكلاس
خصائص الـ Instance مقابل الخصائص الساكنة (Static)الثوابت في الكلاساتالدوال والخصائص الساكنة (Static)الخصائص الخاصة (Private) والمحمية (Protected)خصائص للقراءة فقط (Readonly) في PHP 8.1مراجعة - مدير الحساب البنكي6تعدد الأشكال (Polymorphism)
مراجعة إعادة تعريف الدوال (Method Overriding)تعدد الأشكال عبر الـ Interfacesتلميح النوع (Type Hinting) وأنواع الاتحاد (Union Types)الربط الاستاتيكي المتأخر (Late Static Binding)ملخص - معالج الدفع (Payment Processor)