Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

الواجهة مقابل الـ Abstract Class

جزء من قسم البرمجة كائنية التوجه في رحلة PHP على Coddy. الدرس 30 من 91.

الآن بعد أن تعلّمت كلًّا من الواجهات والفئات المجرّدة، لنوضّح متى تستخدم كلًّا منهما. رغم أنهما قد تبدوان متشابهتين، فإن لكلٍّ منهما أغراضًا مختلفة وإمكانات مميّزة.

الميزة الواجهة الفئة المجرّدة
الأساليب توقيعات الأساليب فقط أساليب مجرّدة وملموسة
الخصائص الثوابت فقط يمكن أن تحتوي على خصائص
التوريث المتعدد يمكن للفئة أن تنفّذ العديد منها يمكن للفئة أن تمدّد فئة واحدة فقط
الباني يمكنها التصريح بتوقيع __construct (من دون جسم) يمكنها تعريف باني مع جسم

استخدم interface عندما تريد تعريف عقد يمكن للأصناف غير المرتبطة الوفاء به. على سبيل المثال، قد يطبّق كلٌّ من Printer وLogger واجهة Writable، رغم أنهما لا يشتركان في سلف مشترك.

استخدم abstract class عندما تكون لديك فئات مترابطة تشترك في تعليمات برمجية مشتركة. إذا كانت فئتا Dog وCat تحتاجان كلتاهما إلى تطبيق أسلوب eat() نفسه، تتيح لك فئة Animal مجردة كتابة ذلك التعليمات البرمجية مرة واحدة.

يمكنك أيضًا الجمع بين النهجين. يمكن لفئة أن ترث من فئة abstract مع تنفيذ واجهات متعددة:

<?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";
    }
}

النقطة الأساسية: اختر الواجهات لتعريف القدرات عبر الفئات غير المرتبطة. اختر الفئات المجرّدة عندما تحتاج إلى مشاركة التعليمات البرمجية بين الفئات المرتبطة.

challenge icon

التحدي

سهل

لنبنِ نظامًا للمركبات يوضّح متى نستخدم abstract class بدلًا من interface، وكيف ندمج النهجين بفعالية.

ستنشئ نظامًا تشترك فيه المركبات في property مشتركة من خلال الوراثة، ولكن يمكنها أيضًا اكتساب إمكانات إضافية من خلال interface. وهذا يحاكي قرارات التصميم في العالم الحقيقي: السيارة «is a» مركبة (وراثة)، لكنها أيضًا «has the capability» لأن تكون قابلة لإعادة التزوّد بالوقود (interface).

نظّم كودك عبر أربعة ملفات:

  • Refuelable.php: عرّف interface باسم Refuelable مع method واحدة فقط: refuel($amount). يمكن تطبيق هذه الإمكانية على أي class تحتاج إلى إعادة التزوّد بالوقود، بغضّ النظر عن تسلسل الوراثة الخاص بها.
  • Vehicle.php: عرّف abstract class باسم Vehicle توفّر الوظائف المشتركة لجميع المركبات. يجب أن تحتوي على property محمية باسم $brand وproperty محمية باسم $fuelLevel (تبدأ بالقيمة 0). يستقبل constructor اسم العلامة التجارية. أدرج method ملموسة باسم getBrand() تُرجع العلامة التجارية، وmethod ملموسة باسم getFuelLevel() تُرجع مستوى الوقود الحالي، وmethod abstract باسم drive() يجب على الفئات الابنة تنفيذها.
  • Car.php: أنشئ class باسم Car يمتد من Vehicle ويطبّق Refuelable. أدرج الملفين المطلوبين في الأعلى. يستقبل constructor العلامة التجارية ويمرّرها إلى constructor الخاص بـ parent. نفّذ drive() لإرجاع "[brand] car is driving". نفّذ refuel($amount) لإضافة المبلغ إلى مستوى الوقود وإرجاع "[brand] refueled to [fuelLevel] liters".
  • main.php: أدرج ملف Car. ستتلقى مدخلين: اسم علامة تجارية ومقدار الوقود (حوّله إلى عدد صحيح). أنشئ Car باستخدام العلامة التجارية. اطبع نتيجة drive() في السطر الأول، ثم اطبع نتيجة refuel() مع مقدار الوقود في السطر الثاني.

يوضّح هذا التحدي التمييز الأساسي: تشارك abstract class المسماة Vehicle الكود وتؤسس علاقة «is-a»، بينما يضيف interface المسمى Refuelable إمكانية يمكن أن تنطبق على فئات أخرى غير مرتبطة (مثل مولّد أو قارب) من دون الحاجة إلى أن تكون مركبات.

جرّب بنفسك

<?php
require_once 'Car.php';

// اقرأ المدخلات
$brand = trim(fgets(STDIN));
$fuelAmount = intval(trim(fgets(STDIN)));

// TODO: أنشئ Car بالـ brand

// TODO: اطبع نتيجة drive() في السطر الأول

// TODO: اطبع نتيجة refuel() مع كمية الوقود في السطر الثاني
?>
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم PHP عبر الإنترنت