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

لماذا لا توجد وراثة متعددة للكلاسات

جزء من قسم Object Oriented Programming في رحلة Java على Coddy — الدرس 26 من 87.

تمنع لغة Java بشكل متعمد أي فئة (class) من وراثة أكثر من فئة واحدة. يوجد هذا القيد بسبب مشكلة تُعرف باسم مشكلة الماس (Diamond Problem).

تخيل لو كانت لغة Java تسمح بالوراثة المتعددة. فكر في هذا السيناريو الافتراضي:

// هذا الكود غير صالح في Java
public class A {
    public void greet() {
        System.out.println("Hello from A");
    }
}

public class B extends A {
    @Override
    public void greet() {
        System.out.println("Hello from B");
    }
}

public class C extends A {
    @Override
    public void greet() {
        System.out.println("Hello from C");
    }
}

// غير مسموح به في Java!
public class D extends B, C { }

إذا قمت باستدعاء greet() على كائن D، فأي نسخة يجب أن تعمل؟ تلك الخاصة بـ B أم C؟ هذا الغموض هو "مشكلة الماس" (Diamond Problem)، والتي سميت بهذا الاسم نسبة إلى شكل الماسة الناتج عن مخطط الوراثة.

حل جافا بسيط: السماح بالوراثة الفردية فقط للفئات. ومع ذلك، توفر جافا بديلاً. يمكن للفئة تنفيذ واجهات متعددة، والتي ستتعلم عنها في فصل قادم.

تعالج الواجهات مشكلة الماس (diamond problem) بشكل مختلف وتمنحك المرونة دون غموض.

// هذا صالح في Java
public class Dog extends Animal implements Runnable, Comparable<Dog> {
    // يمكن تنفيذ واجهات متعددة
}

هذا الخيار التصميمي يحافظ على نموذج الوراثة في Java نظيفاً وقابلاً للتوقع، مع السماح في الوقت نفسه بإعادة استخدام قوية للكود من خلال الواجهات (interfaces).

challenge icon

التحدي

سهل

لنقم ببناء نظام مشغل موسيقى يوضح قاعدة الوراثة الأحادية في Java وكيف لا يزال بإمكانك تحقيق تصميمات مرنة ضمن هذا القيد.

تخيل أنك تريد إنشاء مكبر صوت ذكي يجمع بين ميزات كل من مشغل الموسيقى والمساعد الصوتي. نظرًا لأن Java لا تسمح بتوسيع فئات متعددة، فستحتاج إلى تصميم التسلسل الهرمي الخاص بك بعناية باستخدام الوراثة الأحادية.

ستقوم بإنشاء أربعة ملفات لتنظيم الكود الخاص بك:

  • AudioDevice.java: قم بإنشاء الفئة الأساسية التي تشترك فيها جميع الأجهزة التي تشغل الصوت. يجب أن تحتوي على:
    • حقل خاص لـ deviceName (String)
    • منشئ (constructor) يقبل اسم الجهاز
    • دالة getDeviceName() تعيد الاسم
    • دالة playSound() تطبع: [deviceName]: Playing audio
  • MusicPlayer.java: قم بإنشاء فئة ترث من AudioDevice وتضيف ميزات خاصة بالموسيقى:
    • حقل خاص لـ currentSong (String)
    • منشئ يأخذ اسم الجهاز ويستخدم super(deviceName)
    • دالة setSong(String song) لتعيين الأغنية الحالية
    • تجاوز (Override) لدالة playSound() لتطبع: [deviceName]: Now playing - [currentSong]
  • SmartSpeaker.java: قم بإنشاء فئة ترث من MusicPlayer (وليس من كل من MusicPlayer وفئة VoiceAssistant أخرى - فهذا سيكون وراثة متعددة!). يعتمد مكبر الصوت الذكي على مشغل الموسيقى من خلال إضافة ميزات صوتية:
    • حقل خاص لـ assistantName (String)
    • منشئ يأخذ اسم الجهاز واسم المساعد، باستخدام super(deviceName)
    • دالة voiceCommand(String command) تطبع: [assistantName]: Processing "[command]"
    • دالة getFullInfo() تطبع: [deviceName] with [assistantName] assistant
  • Main.java: استعرض سلسلة الوراثة متعددة المستويات الخاصة بك. ستتلقى ثلاثة مدخلات: اسم الجهاز (String)، واسم المساعد (String)، واسم الأغنية (String). قم بإنشاء SmartSpeaker، وعيّن أغنية، ثم استدعِ هذه الدوال بالترتيب:
    • getFullInfo()
    • playSound()
    • voiceCommand("skip to next")

ستتلقى ثلاثة مدخلات: اسم الجهاز، واسم المساعد، واسم الأغنية.

لاحظ كيف يكتسب SmartSpeaker قدرات الموسيقى من خلال وراثة MusicPlayer في سلسلة (AudioDevice -> MusicPlayer -> SmartSpeaker)، بدلاً من محاولة وراثة فئات متعددة غير مرتبطة. هذا هو نهج Java للحفاظ على الوراثة نظيفة وغير غامضة!

ورقة مرجعية

تسمح لغة Java فقط بـ الوراثة الفردية (single inheritance) - حيث يمكن للفئة (class) أن ترث من فئة واحدة أخرى فقط. هذا يمنع مشكلة الألماسة (Diamond Problem)، حيث ينشأ الغموض إذا كان بإمكان الفئة وراثة نفس الطريقة (method) من فئات أب متعددة.

// غير مسموح به في Java - الوراثة المتعددة
public class D extends B, C { } // خطأ!

ومع ذلك، تسمح Java للفئة بتنفيذ عدة واجهات (interfaces) كبديل:

// صالح في Java
public class Dog extends Animal implements Runnable, Comparable<Dog> {
    // يمكن توسيع فئة واحدة وتنفيذ واجهات متعددة
}

تدعم Java الوراثة متعددة المستويات (multilevel inheritance) - إنشاء سلاسل وراثة:

public class AudioDevice { }

public class MusicPlayer extends AudioDevice { }

public class SmartSpeaker extends MusicPlayer { }
// يرث SmartSpeaker من كل من MusicPlayer و AudioDevice

جرّب بنفسك

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // قراءة المدخلات
        String deviceName = scanner.nextLine();
        String assistantName = scanner.nextLine();
        String songName = scanner.nextLine();
        
        // TODO: قم بإنشاء SmartSpeaker باستخدام deviceName و assistantName
        
        // TODO: قم بتعيين الأغنية باستخدام setSong()
        
        // TODO: قم باستدعاء getFullInfo()
        
        // TODO: قم باستدعاء playSound()
        
        // TODO: قم باستدعاء voiceCommand("skip to next")
    }
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming