أساسيات تعدد الأشكال
جزء من قسم Object Oriented Programming في رحلة Dart على Coddy — الدرس 57 من 110.
تعدد الأشكال (Polymorphism) يعني "أشكالاً متعددة" - وهي القدرة على التعامل مع كائنات من فئات (classes) مختلفة من خلال واجهة مشتركة. عندما يكون لديك مرجع لفئة أب (parent class reference)، يمكنه الإشارة إلى أي كائن من فئة ابن (child class object)، ويتم استدعاء الطريقة (method) الصحيحة بناءً على نوع الكائن الفعلي.
هذا أمر قوي لأنه يمكنك كتابة كود يعمل مع النوع الأب، ومع ذلك فإنه يتعامل تلقائياً مع جميع الأنواع الأبناء بشكل صحيح:
class Animal {
void speak() => print('Some sound');
}
class Dog extends Animal {
@override
void speak() => print('Woof!');
}
class Cat extends Animal {
@override
void speak() => print('Meow!');
}
void main() {
Animal myPet = Dog(); // نوع الأب، كائن الابن
myPet.speak(); // المخرجات: Woof!
myPet = Cat(); // نفس المتغير، كائن مختلف
myPet.speak(); // المخرجات: Meow!
}المتغير myPet تم تعريفه كـ Animal، ولكنه يحمل Dog أو Cat. عندما يتم استدعاء speak()، تنظر Dart إلى نوع الكائن الفعلي في وقت التشغيل وتستدعي الطريقة المناسبة التي تم تجاوزها.
يمكّنك هذا من كتابة دوال مرنة تعمل مع أي فئة فرعية:
void makeAllSpeak(List<Animal> animals) {
for (var animal in animals) {
animal.speak(); // كل حيوان يتحدث بطريقته الخاصة
}
}
void main() {
var pets = [Dog(), Cat(), Dog()];
makeAllSpeak(pets);
// المخرجات: Woof! Meow! Woof!
}لا تحتاج الدالة إلى معرفة أي شيء عن Dog أو Cat - فهي تعمل ببساطة مع Animal. هذا يجعل كودك أكثر قابلية للتوسع لأن إضافة أنواع حيوانات جديدة لا تتطلب أي تغييرات في الدوال الحالية.
التحدي
سهللنقم ببناء نظام آلات موسيقية يوضح تعدد الأشكال (polymorphism) بشكل عملي. ستقوم بإنشاء فئة أساسية باسم Instrument وعدة أنواع من الآلات، ثم كتابة دالة يمكنها جعل أي مجموعة من الآلات تعزف معاً - دون معرفة أنواعها المحددة.
ستقوم بتنظيم الكود الخاص بك في ملفين:
instruments.dart: حدد التسلسل الهرمي للآلات هنا:- فئة
Instrumentمع خاصيةString nameومنشئ (constructor). قم بتضمين تابعplay()يطبع[name] makes a sound - فئة
Guitarترث منInstrumentوتعمل على تجاوز (override) التابعplay()ليطبع[name] strums melodically - فئة
Drumترث منInstrumentوتعمل على تجاوزplay()ليطبع[name] beats rhythmically - فئة
Pianoترث منInstrumentوتعمل على تجاوزplay()ليطبع[name] plays harmoniously
performConcert(List<Instrument> instruments)تطبعConcert begins!، ثم تمر عبر القائمة وتستدعيplay()لكل آلة، وفي النهاية تطبعConcert ends!- فئة
main.dart: استورد ملف الآلات الخاص بك واستعرض تعدد الأشكال من خلال إنشاء فرقة موسيقية مختلطة:- أنشئ قائمة من نوع
List<Instrument>تحتوي علىGuitarباسم'Acoustic'، وDrumباسم'Snare'، وPianoباسم'Grand' - قم بتمرير هذه القائمة إلى
performConcert()
- أنشئ قائمة من نوع
لاحظ كيف تعمل performConcert() مع النوع الأب Instrument، ومع ذلك تعزف كل آلة بطريقتها الفريدة. هذا هو تعدد الأشكال (polymorphism) - حيث يؤدي استدعاء نفس التابع إلى سلوك مختلف بناءً على النوع الفعلي للكائن.
المخرجات المتوقعة:
Concert begins!
Acoustic strums melodically
Snare beats rhythmically
Grand plays harmoniously
Concert ends!ورقة مرجعية
تعدد الأشكال (Polymorphism) يعني "أشكالاً متعددة" - فهو يسمح لك بالتعامل مع كائنات من فئات مختلفة من خلال واجهة مشتركة. يمكن لمرجع الفئة الأب أن يشير إلى أي كائن من الفئة الابن، ويتم استدعاء الطريقة الصحيحة بناءً على نوع الكائن الفعلي في وقت التشغيل.
مثال أساسي على تعدد الأشكال:
class Animal {
void speak() => print('Some sound');
}
class Dog extends Animal {
@override
void speak() => print('Woof!');
}
class Cat extends Animal {
@override
void speak() => print('Meow!');
}
void main() {
Animal myPet = Dog(); // نوع الأب، كائن الابن
myPet.speak(); // المخرجات: Woof!
myPet = Cat(); // نفس المتغير، كائن مختلف
myPet.speak(); // المخرجات: Meow!
}يتيح تعدد الأشكال وظائف مرنة تعمل مع أي فئة فرعية:
void makeAllSpeak(List<Animal> animals) {
for (var animal in animals) {
animal.speak(); // كل حيوان يتحدث بطريقته الخاصة
}
}
void main() {
var pets = [Dog(), Cat(), Dog()];
makeAllSpeak(pets);
// المخرجات: Woof! Meow! Woof!
}تعمل الوظيفة مع النوع الأب Animal دون الحاجة إلى معرفة فئات الأبناء المحددة مثل Dog أو Cat. وهذا يجعل الكود أكثر قابلية للتوسع - فإضافة أنواع جديدة لا تتطلب أي تغييرات على الوظائف الحالية.
جرّب بنفسك
import 'instruments.dart';
void main() {
// TODO: قم بإنشاء List<Instrument> تحتوي على:
// - Guitar باسم 'Acoustic'
// - Drum باسم 'Snare'
// - Piano باسم 'Grand'
// TODO: قم باستدعاء performConcert() مع قائمة الآلات الخاصة بك
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات الـ OOP
الملفات الخارجيةالمكتبات والـ Importsمقدمة في الـ OOPالـ Classes مقابل الـ Objectsالكلمة المفتاحية thisالـ Methodsمتغيرات الـ Instanceأساسيات الـ Constructorمراجعة - آلة حاسبة بسيطة4أمان الـ Null
مقدمة في أمان الـ NullNullable مقابل Non-Nullableعاملا الـ ? و !الكلمة المفتاحية Late وأمان الـ Nullالعوامل المدركة للـ Nullأمان الـ Null في الـ Classesمراجعة - نظام ملف تعريف المستخدم7الفئات المجردة والواجهات
الفئات المجردةالدوال المجردةالواجهات في Dartالواجهات الضمنيةالتنفيذ مقابل التوسيعالواجهات المتعددةمراجعة - حاسبة الأشكال10المجموعات والأنماط العامة
نظرة عامة على List و Set و Mapالمجموعات آمنة النوعالفئات العامةالدوال العامةقيود الأنماط العامةIterable و Iteratorملخص - التخزين العام13مفاهيم OOP المتقدمة
التركيب مقابل الوراثة (Composition vs Inheritance)دوال التوسعة (Extension Methods)الأصناف القابلة للاستدعاء (Callable Classes)الأصناف المختومة (Sealed Classes - Dart 3)السجلات (Records - Dart 3)الأنماط والمطابقة (Patterns & Matching - 3.0)التعدادات مع الدوال (Enums with Methods)2المنشئات في Dart
المنشئ الافتراضيالمنشئات المسماةقوائم التهيئةالمنشئات الثابتةالمنشئات المصنعيةالمنشئات الموجهةملخص - بناء الأشكال5التغليف (Encapsulation)
الأعضاء العامة مقابل الخاصةاتفاقية البادئة _الخصوصية على مستوى المكتبةتعمق في Getters و Settersإخفاء المعلوماتمراجعة - سجلات الطلاب8Mixins
مقدمة إلى Mixinsإنشاء Mixinsاستخدام Mixins متعددةالكلمة المفتاحية on في MixinsMixin مقابل الوراثة (Inheritance)Mixin مقابل الواجهة (Interface)مراجعة - نظام الحيوانات (Animal System)3خصائص الـ Class
أعضاء الـ Instance مقابل الـ Staticحقول Final و Constمتغيرات Lateالـ Static Methods والحقولدوال الـ Getters والـ Settersمراجعة - مدير الحساب البنكي6الوراثة
أساسيات الوراثةالكلمة المفتاحية superإعادة تعريف الدوال (Method Overriding)الوسم @overrideالكلمة المفتاحية final Classالدوال البانية والوراثةمراجعة - هيكلية الموظفين9تعدد الأشكال
أساسيات تعدد الأشكالتعدد الأشكال عبر الـ Interfacesالتحقق من النوع أثناء التشغيلالمعاملات is و asالكلمة المفتاحية Covariantملخص - معالج الدفع12البرمجة الكائنية غير المتزامنة (Async OOP)
Futures و async/awaitأساسيات الـ Streamsمتحكمات الـ Streamsالـ Constructors غير المتزامنةالعمليات غير المتزامنة في دوال الكلاسمراجعة - جالب البيانات (Data Fetcher)15أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المستودع