تعدد الأشكال

تعدد الأشكال (Polymorphism) يعني "أشكال متعددة". يسمح لك بتنفيذ سلوكيات مختلفة لنفس الواجهة.

مفهوم تعدد الأشكال

المفهوم الوصف
تعدد الأشكال نفس الاسم، سلوكيات مختلفة
النوع المرجعي نوع المتغير (الفئة الأصلية)
النوع الفعلي نوع الكائن الحقيقي (الفئة الفرعية)

مثال أساسي

JAVA
public class Animal {
    public void makeSound() {
        System.out.println("صوت عام");
    }
}

public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("ووف ووف!");
    }
}

public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("موو!");
    }
}

// الاستخدام
Animal animal1 = new Dog();
Animal animal2 = new Cat();

animal1.makeSound();  // ووف ووف!
animal2.makeSound();  // موو!

تعدد الأشكال مع المصفوفات

JAVA
Animal[] animals = {
    new Dog("ريكس", 3، "جيرمن"),
    new Cat("لوسي", 2، true),
    new Dog("بودي", 5، "لابرادور")
};

for (Animal animal : animals) {
    animal.makeSound();  // كل حيوان يصدر صوته المختلف
}

تعدد الأشكال مع المعلمات

JAVA
public class AnimalShelter {
    public void careFor(Animal animal) {
        System.out.println("العناية بـ: " + animal.getName());
        animal.eat();
        animal.makeSound();
    }
}

// الاستخدام
AnimalShelter shelter = new AnimalShelter();
shelter.careFor(new Dog("ريكس", 3، "جيرمن"));
shelter.careFor(new Cat("لوسي", 2، true));

Casting — تحويل الأنواع

Upcasting (تلقائي)

JAVA
Dog dog = new Dog("ريكس", 3، "جيرمن");
Animal animal = dog;  // تلقائي — Dog هو Animal
animal.makeSound();    // ووف ووف!

Downcasting (يدوي)

JAVA
Animal animal = new Dog("ريكس", 3، "جيرمن");
// Dog dog = animal;  // ❌ خطأ
Dog dog = (Dog) animal;  // ✅ صحيح
dog.bark();

التحقق قبل التحويل

JAVA
Animal animal = new Cat("لوسي", 2، true);

if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
    dog.bark();
} else if (animal instanceof Cat) {
    Cat cat = (Cat) animal;
    cat.meow();
}

مثال كامل: نظام الدفع

JAVA
public abstract class Payment {
    protected double amount;
    protected String date;
    
    public Payment(double amount, String date) {
        this.amount = amount;
        this.date = date;
    }
    
    public abstract boolean processPayment();
    public abstract String getReceipt();
}

public class CreditCardPayment extends Payment {
    private String cardNumber;
    
    public CreditCardPayment(double amount, String date, String cardNumber) {
        super(amount, date);
        this.cardNumber = cardNumber;
    }
    
    @Override
    public boolean processPayment() {
        System.out.println("معالجة الدفع بالبطاقة: " + cardNumber);
        return true;
    }
    
    @Override
    public String getReceipt() {
        return "إيصال بطاقة ائتمان: " + amount + " ريال";
    }
}

public class CashPayment extends Payment {
    public CashPayment(double amount, String date) {
        super(amount, date);
    }
    
    @Override
    public boolean processPayment() {
        System.out.println("معالجة الدفع النقدي");
        return true;
    }
    
    @Override
    public String getReceipt() {
        return "إيصال نقدي: " + amount + " ريال";
    }
}

// الاستخدام
Payment[] payments = {
    new CreditCardPayment(100, "2026-06-25"، "1234-5678"),
    new CashPayment(50، "2026-06-25")
};

for (Payment payment : payments) {
    payment.processPayment();
    System.out.println(payment.getReceipt());
}

❓ أسئلة شائعة

س ما هو Dynamic Dispatch؟
ج هو الآلية التي يختار بها Java الدالة الصحيحة أثناء التشغيل بناءً على نوع الكائن الفعلي.
س لماذا نحتاج Downcasting؟
ج عندما نريد الوصول لدوال خاصة بالفئة الفرعية.
س هل يمكن تجاوز الدوال الثابتة (static)؟
ج لا، الدوال الثابتة لا يمكن تجاوزها لأنها مرتبطة بالفئة وليس بالكائن.

📖 ملخص

📝 تمارين

  1. حيوانات: أنشئ 5 فئات حيوانات مع سلوكيات مختلفة
  2. أشكال: أنشئ فئات أشكال مع دوال لحساب المساحة والمحيط
  3. وظائف: أنشئ فئات وظائف مع رواتب ومكافآت مختلفة

الدرس التالي

في الدرس التالي، سنتعلم الواجهات و Lambda — الواجهات والدوال المجردة.

100%