الوراثة (Inheritance) وتعددية الأشكال في Dart لبناء هيكل برمجي قوي


الوراثة (Inheritance) وتعددية الأشكال في Dart لبناء هيكل برمجي قوي

سنتعلم اليوم كيف نستخدم الوراثة وتعددية الأشكال في Dart لتصميم هياكل برمجية مرنة وقابلة للتوسع، مما يعزز من قوة تطبيقات Flutter لدينا.

مقدمة: فهم المبادئ الأساسية

تعتبر الوراثة (Inheritance) وتعددية الأشكال (Polymorphism) من الركائز الأساسية للبرمجة كائنية التوجه (OOP)، وتوفر Dart دعماً قوياً لهما. تسمح لنا الوراثة بإنشاء فئات جديدة (فئات مشتقة) تعتمد على فئات موجودة (فئات أساسية)، مما يمكنها من إعادة استخدام الخصائص والسلوكيات وتوسيعها. أما تعددية الأشكال، فتسمح للكائنات ذات الأنواع المختلفة بالاستجابة لنفس الاستدعاء بطرقها الخاصة، مما يجعل الكود أكثر مرونة وقابلية للتوسع.

ملاحظة تقنية: تذكر أن extends هي الكلمة المفتاحية في Dart لتطبيق الوراثة، وأن @override تُستخدم للإشارة إلى أننا نلغي سلوكًا موجودًا في الفئة الأساسية، مما يحسن من قابلية قراءة الكود ويكتشف الأخطاء المحتملة في وقت الترجمة.

الخطوة 1: بناء الفئة الأساسية (Base Class)

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

class Animal {
  String name; // خاصية لاسم الحيوان

  Animal(this.name); // مُنشئ الفئة الأساسية الذي يستقبل الاسم

  void makeSound() {
    print('$name يصدر صوتاً عاماً.'); // وظيفة عامة لإصدار الصوت
  }
}

الخطوة 2: تطبيق الوراثة (Inheritance)

الآن، سنقوم بإنشاء فئات مشتقة مثل Dog و Cat ترث من الفئة Animal. كل فئة مشتقة ستقوم بتجاوز (override) وظيفة makeSound() لتعطيها سلوكاً خاصاً بها، وقد تضيف أيضاً وظائف فريدة.

class Dog extends Animal {
  // مُنشئ الكلب، يستدعي مُنشئ الفئة الأب باستخدام super
  Dog(String name) : super(name);

  @override // للإشارة إلى أننا نلغي وظيفة من الفئة الأب
  void makeSound() {
    print('$name ينبح: هاو هاو!'); // سلوك خاص بالكلب
  }

  void fetch() {
    print('$name يحضر الكرة.'); // وظيفة إضافية خاصة بالكلب
  }
}

class Cat extends Animal {
  // مُنشئ القط، يستدعي مُنشئ الفئة الأب
  Cat(String name) : super(name);

  @override
  void makeSound() {
    print('$name يموء: مياو مياو!'); // سلوك خاص بالقط
  }

  void scratch() {
    print('$name يخدش الأثاث.'); // وظيفة إضافية خاصة بالقط
  }
}

الخطوة 3: تعددية الأشكال (Polymorphism) والاستخدام

في هذه الخطوة، سنرى كيف يمكننا استخدام تعددية الأشكال. سننشئ قائمة من نوع Animal ولكننا سنضع فيها كائنات من نوع Dog و Cat. عندما نستدعي وظيفة makeSound() على كل عنصر في القائمة، ستستدعى النسخة الصحيحة من الوظيفة بناءً على النوع الفعلي للكائن.

void main() {
  // إنشاء كائنات من الفئات المشتقة
  var myDog = Dog('بوبي');
  var myCat = Cat('مشمش');

  // استخدام تعددية الأشكال: قائمة من نوع Animal يمكنها حمل كائنات Dog و Cat
  List<Animal> farmAnimals = [myDog, myCat, Dog('لوسي'), Cat('لولو')];

  print('--- أصوات الحيوانات في المزرعة ---');
  for (var animal in farmAnimals) {
    animal.makeSound(); // استدعاء makeSound() سيستدعي النسخة الخاصة بكل كائن

    // التحقق من نوع الكائن لتنفيذ وظائفه الخاصة (إن وجدت)
    if (animal is Dog) {
      animal.fetch(); // يمكن للكلاب إحضار الأشياء
    } else if (animal is Cat) {
      animal.scratch(); // يمكن للقطط الخدش
    }
  }

  print('\n--- كائنات فردية ---');
  myDog.makeSound();
  myDog.fetch(); // يمكن استدعاء الوظيفة الخاصة مباشرة
  myCat.makeSound();
  myCat.scratch();
}

الكود النهائي الكامل

إليك الكود كاملاً القابل للنسخ والتشغيل في بيئة Dart (Flutter Framework):

class Animal {
  String name; // خاصية لاسم الحيوان

  Animal(this.name); // مُنشئ الفئة الأساسية الذي يستقبل الاسم

  void makeSound() {
    print('$name يصدر صوتاً عاماً.'); // وظيفة عامة لإصدار الصوت
  }
}

class Dog extends Animal {
  // مُنشئ الكلب، يستدعي مُنشئ الفئة الأب باستخدام super
  Dog(String name) : super(name);

  @override // للإشارة إلى أننا نلغي وظيفة من الفئة الأب
  void makeSound() {
    print('$name ينبح: هاو هاو!'); // سلوك خاص بالكلب
  }

  void fetch() {
    print('$name يحضر الكرة.'); // وظيفة إضافية خاصة بالكلب
  }
}

class Cat extends Animal {
  // مُنشئ القط، يستدعي مُنشئ الفئة الأب
  Cat(String name) : super(name);

  @override
  void makeSound() {
    print('$name يموء: مياو مياو!'); // سلوك خاص بالقط
  }

  void scratch() {
    print('$name يخدش الأثاث.'); // وظيفة إضافية خاصة بالقط
  }
}

void main() {
  // إنشاء كائنات من الفئات المشتقة
  var myDog = Dog('بوبي');
  var myCat = Cat('مشمش');

  // استخدام تعددية الأشكال: قائمة من نوع Animal يمكنها حمل كائنات Dog و Cat
  List<Animal> farmAnimals = [myDog, myCat, Dog('لوسي'), Cat('لولو')];

  print('--- أصوات الحيوانات في المزرعة ---');
  for (var animal in farmAnimals) {
    animal.makeSound(); // استدعاء makeSound() سيستدعي النسخة الخاصة بكل كائن

    // التحقق من نوع الكائن لتنفيذ وظائفه الخاصة (إن وجدت)
    if (animal is Dog) {
      animal.fetch(); // يمكن للكلاب إحضار الأشياء
    } else if (animal is Cat) {
      animal.scratch(); // يمكن للقطط الخدش
    }
  }

  print('\n--- كائنات فردية ---');
  myDog.makeSound();
  myDog.fetch(); // يمكن استدعاء الوظيفة الخاصة مباشرة
  myCat.makeSound();
  myCat.scratch();
}

النتيجة المتوقعة

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

--- أصوات الحيوانات في المزرعة ---
بوبي ينبح: هاو هاو!
بوبي يحضر الكرة.
مشمش يموء: مياو مياو!
مشمش يخدش الأثاث.
لوسي ينبح: هاو هاو!
لوسي يحضر الكرة.
لولو يموء: مياو مياو!
لولو يخدش الأثاث.

--- كائنات فردية ---
بوبي ينبح: هاو هاو!
بوبي يحضر الكرة.
مشمش يموء: مياو مياو!
مشمش يخدش الأثاث.