تعدد الأشكال
أمر واحد، وكل كائن ينفّذه بطريقته. ⏱ نحو 20 دقيقة.
- تشرح تعدد الأشكال بمثال من الحياة.
- تكتب دالة بالاسم نفسه في كلاسات مختلفة.
- تستدعي الدالة نفسها على قائمة كائنات مختلفة.
- تلخّص مبادئ البرمجة الشيئية الأربعة.
١أمر واحد، وأشكال كثيرة
تقول للطلاب «قدّموا أنفسكم»، فيقول كل واحد كلامًا مختلفًا. الأمر واحد، والتنفيذ يختلف حسب الشخص. هذا هو تعدد الأشكال: دالة بالاسم نفسه في كلاسات مختلفة، وكل كلاس ينفّذها بطريقته.
class Dog: def speak(self): print("هو هو") class Cat: def speak(self): print("مياو") for animal in [Dog(), Cat(), Dog()]: animal.speak()
الحلقة لا تسأل «هل هذا كلب أم قط؟». تكتب animal.speak() فقط، وكل كائن يعرف ما يفعله.
٢مع الوراثة: الأشكال الهندسية
غالبًا نجمع تعدد الأشكال مع الوراثة: الأب يحدد اسم الدالة، وكل ابن يعيد تعريفها بطريقته:
class Shape: def area(self): return 0 class Square(Shape): def __init__(self, side): self.side = side def area(self): return self.side * self.side class Circle(Shape): def __init__(self, r): self.r = r def area(self): return round(3.14 * self.r * self.r, 2) shapes = [Square(4), Circle(2), Square(3)]for s in shapes: print(s.area())
٣لماذا هو مفيد؟
لو أضفنا شكلًا جديدًا (مستطيلًا مثلًا) فإننا نكتب كلاسه فقط، ولا نغيّر الحلقة أبدًا. قارن:
for s in shapes: if type(s) == Square: print(s.side * s.side) elif type(s) == Circle: print(3.14 * s.r * s.r)
for s in shapes: print(s.area())
في الطريقة الأولى نعدّل الحلقة مع كل شكل جديد. في الثانية الحلقة ثابتة، وكل شكل يحسب مساحته بنفسه.
٤ملخص البرمجة الشيئية
| المبدأ | الفكرة | في بايثون |
|---|---|---|
| الكلاس والكائن | قالب ونسخ منه | class و Car() |
| التغليف | حماية البيانات | self.__balance |
| الوراثة | الابن يأخذ من الأب | class Student(Person) |
| تعدد الأشكال | أمر واحد وتنفيذ مختلف | دالة بالاسم نفسه في كل كلاس |
📎 للاستزادة (اختياري): أنت تستخدم تعدد الأشكال منذ البداية
الدالة len تعمل مع النص ومع القائمة، والعلامة + تجمع الأعداد وتلصق النصوص. أمر واحد وسلوك يختلف حسب النوع.
📎 للاستزادة (اختياري): الكلاس المجرد
أحيانًا نكتب كلاسًا أبًا لا نصنع منه كائنات، بل هو قالب يُلزم كل ابن بكتابة دوال معيّنة، مثل Shape الذي يُلزم كل شكل بدالة area. يسمى الكلاس المجرد، وستدرسه بالتفصيل في مقرر لاحق.
توقّع وتحقّق
ما معنى تعدد الأشكال؟
في الحلقة for s in shapes: print(s.area()) من يحدد طريقة حساب المساحة؟
area بطريقته.عند إضافة شكل جديد، ماذا نكتب؟
أي مبدأ يحمي البيانات داخل الكائن؟
الخلاصة
- تعدد الأشكال: دالة بالاسم نفسه، وكل كلاس ينفّذها بطريقته.
- نستدعي الدالة على كل الكائنات دون فحص نوعها.
- إضافة نوع جديد لا تحتاج تعديل الحلقة.
- المبادئ الأربعة: الكلاس والكائن، والتغليف، والوراثة، وتعدد الأشكال.
تحدٍّ برمجي: الموظفون والرواتب
متقدماكتب كلاسين: Employee و Manager، لكل منهما __init__ تحفظ الراتب الأساسي، ودالة pay. موظف عادي: pay تُرجع الراتب كما هو. المدير: pay تُرجع الراتب + 2000. ضع في قائمة موظفًا براتب 5000 ومديرًا براتب 7000، واطبع pay لكل منهما بحلقة، ثم المجموع.
- Manager يرث من Employee.
- أعد تعريف pay في Manager.
- الحلقة تستدعي
p.pay()فقط. - اطبع: المجموع: ثم القيمة.
ابدأ من هذا الكود، واضغط ▶ شغّل هنا لتكتب حلّك وتجرّبه مباشرة:
class Employee: def __init__(self, salary): self.salary = salary
💡 تلميح 1
class Manager(Employee):💡 تلميح 2
return self.salary + 2000حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.
class Employee: def __init__(self, salary): self.salary = salary def pay(self): return self.salary class Manager(Employee): def pay(self): return self.salary + 2000 staff = [Employee(5000), Manager(7000)]total = 0for p in staff: print(p.pay()) total += p.pay()print("المجموع:", total)