طَبِّقْهاتعلّم المبدأ، وطبّقه بيدكمقرر 111 · أساسيات برمجة الحاسب
الدرس 26 · الوحدة 5: البرمجة الشيئية

تعدد الأشكال

أمر واحد، وكل كائن ينفّذه بطريقته. ⏱ نحو 20 دقيقة.

shape.area()
بعد هذا الدرس ستستطيع أن:
  • تشرح تعدد الأشكال بمثال من الحياة.
  • تكتب دالة بالاسم نفسه في كلاسات مختلفة.
  • تستدعي الدالة نفسها على قائمة كائنات مختلفة.
  • تلخّص مبادئ البرمجة الشيئية الأربعة.

١أمر واحد، وأشكال كثيرة

تقول للطلاب «قدّموا أنفسكم»، فيقول كل واحد كلامًا مختلفًا. الأمر واحد، والتنفيذ يختلف حسب الشخص. هذا هو تعدد الأشكال: دالة بالاسم نفسه في كلاسات مختلفة، وكل كلاس ينفّذها بطريقته.

main.py
class Dog:    def speak(self):        print("هو هو") class Cat:    def speak(self):        print("مياو") for animal in [Dog(), Cat(), Dog()]:    animal.speak()
Shell×
>>> %Run main.py
هو هو
مياو
هو هو
>>>

الحلقة لا تسأل «هل هذا كلب أم قط؟». تكتب animal.speak() فقط، وكل كائن يعرف ما يفعله.

٢مع الوراثة: الأشكال الهندسية

غالبًا نجمع تعدد الأشكال مع الوراثة: الأب يحدد اسم الدالة، وكل ابن يعيد تعريفها بطريقته:

main.py
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())
Shell×
>>> %Run main.py
16
12.56
9
>>>

٣لماذا هو مفيد؟

لو أضفنا شكلًا جديدًا (مستطيلًا مثلًا) فإننا نكتب كلاسه فقط، ولا نغيّر الحلقة أبدًا. قارن:

✗ خطأ
main.py
for s in shapes:    if type(s) == Square:        print(s.side * s.side)    elif type(s) == Circle:        print(3.14 * s.r * s.r)
✓ صواب
main.py
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() فقط.
  • اطبع: المجموع: ثم القيمة.

ابدأ من هذا الكود، واضغط ▶ شغّل هنا لتكتب حلّك وتجرّبه مباشرة:

main.py
class Employee:    def __init__(self, salary):        self.salary = salary
المطلوب×
5000
9000
المجموع: 14000
💡 تلميح 1
class Manager(Employee):
💡 تلميح 2
return self.salary + 2000

حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.

main.py
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)
انتقل إلى تقييم الدرساختيار من متعدد، وصح وخطأ، وأكمل الفراغ، وتتبّع الناتج.ابدأ التقييم ←