
Inheritance في OOP
الوراثة هو أحد أهم المفاهيم في البرمجة كائنية التوجه. فهو يسمح لفئة واحدة بتلقي الخصائص والأساليب من فئة أخرى، مما يسهل إعادة استخدام الكود وتنظيم المنطق ذي الصلة وبناء أنظمة برمجية مرنة.
بدلًا من كتابة نفس الكود مرارًا وتكرارًا في فئات مختلفة، يساعد الوراثة المطورين على إنشاء بنية مشتركة. يمكن للclass العام تحديد السلوك الشائع، بينما يمكن للفئات الأكثر تحديدًا توسيع هذا السلوك وإضافة ميزات خاصة بهم.
مقدمة
في المقالات السابقة من هذه السلسلة OOP، قدمنا الأصناف والكائنات والخصائص والأساليب وconstructors وdestructors. تساعدنا هذه المفاهيم على فهم كيفية إنشاء الكائنات وكيفية تخزين البيانات والسلوك.
يعتمد الوراثة على هذه الأفكار من خلال إظهار كيفية ربط classes ببعضها البعض. في مشاريع البرمجيات الحقيقية، ترتبط العديد من الكائنات. على سبيل المثال، يجوز للمستخدم والمسؤول والمحرر مشاركة معلومات مشتركة مثل الاسم والبريد الإلكتروني وكلمة المرور. ومع ذلك، قد يكون لكل واحد أيضًا أذونات ومسؤوليات مختلفة.
باستخدام الوراثة، يمكننا وضع المنطق المشترك في parent class والسماح للفئات الأخرى أن ترث منه. وهذا يجعل الكود أكثر نظافة، وأسهل في الصيانة، وأكثر تنظيمًا.
ما هو الوراثة في البرمجة كائنية التوجه؟
الوراثة في OOP تعني أن الclass يمكنه استخدام خصائص وأساليب فئة أخرى. عادةً ما يُطلق على class التي توفر الكود المشترك اسم parent class, base class، أو الطبقة الفائقة. تسمى class التي تتلقى هذا الرمز وتوسعه child class, derived class، أو فئة فرعية.
الفكرة الرئيسية بسيطة: إذا كانت عدة فئات تشترك في سلوك مشترك، فلن نحتاج إلى تكرار نفس الكود في كل فئة. بدلًا من ذلك، نحدد السلوك الشائع مرة واحدة في parent class، ثم نسمح للفئات الفرعية بأن ترثه.
على سبيل المثال، جنرال شخص قد تحتوي class على خصائص مثل الاسم والبريد الإلكتروني. أ طالب فئة و أ مدرس يمكن للفئة أن ترث من الشخص لأن كلاهما نوع من الأشخاص. يمكن لكل child class بعد ذلك إضافة خصائصه وأساليبه الخاصة.
لماذا الوراثة مهم
يعد الوراثة أمرًا مهمًا لأنه يدعم إعادة استخدام الكود وتنظيم البرامج بشكل أفضل. وبدون الوراثة، قد يكرر المطورون نفس المنطق في العديد من الأماكن المختلفة. قد يؤدي ذلك إلى صعوبة تحديث التطبيق وزيادة احتمالية احتوائه على أخطاء.
عندما يتم وضع المنطق المشترك في parent class، يمكن إجراء التغييرات في مكان واحد. إذا كانت إحدى الطرق بحاجة إلى تحسين أو كانت هناك حاجة إلى تحديث خاصية مشتركة، فيمكن للمطور تعديل parent class، ويمكن للفئات الفرعية الاستفادة من التغيير.
يساعد الوراثة أيضًا في تمثيل العلاقات الواقعية في الكود. تحتوي العديد من الأنظمة على كائنات ذات نوع عام وأنواع فرعية أكثر تحديدًا. يسمح الوراثة OOP بصياغة هذه العلاقة بشكل واضح.
فئة الوالدين وفئة الطفل
يحتوي parent class على البنية المشتركة. يمكن أن تتضمن الخصائص والأساليب وconstructors والمنطق الآخر الذي يجب أن يكون متاحًا للفئات الفرعية. يرث child class من parent class ويمكنه استخدام أعضائه العامين أو المحميين اعتمادًا على لغة البرمجة ومعدلات الوصول.
يمكن لـ child class أيضًا تحديد خصائص وأساليب إضافية تنتمي إلى child class فقط. يتيح ذلك لـ child class أن يكون أكثر تحديدًا مع الاحتفاظ بالمنطق المشترك من parent class.
على سبيل المثال، تم استدعاء parent class موظف قد تحتوي على الاسم والبريد الإلكتروني والراتب. تم الاتصال بـ child class مدير قد يرث هذه الميزات ويضيف طريقة للموافقة على التقارير. تم إتصال child class آخر المطور قد يرث نفس بيانات الموظف ويضيف طريقة لكتابة الكود أو إدارة المهام.
مثال بسيط للميراث
خذ بعين الاعتبار المثال الأساسي التالي:
class User {
public string $name;
public string $email;
public function login() {
return $this->name . " logged in.";
}
}
class Admin extends User {
public function deletePost() {
return "Post deleted by admin.";
}
}
في هذا المثال، مستخدم class هي parent class. يحتوي على الاسم والبريد الإلكتروني وطريقة تسجيل الدخول. ال مسؤل تمتد class إلى المستخدم، مما يعني أن المشرف يرث خصائص وأساليب المستخدم.
يمكن لكائن المسؤول استخدام طريقة تسجيل الدخول من فئة المستخدم، ويمكنه أيضًا استخدام طريقة الحذف الخاصة به. هذه هي قوة الوراثة: يحافظ child class على الوظيفة المشتركة ويضيف سلوكًا أكثر تحديدًا.
تمتد الكلمة الرئيسية
تستخدم العديد من لغات البرمجة كلمة أساسية لتحديد الوراثة. في PHP، وJava، والعديد من اللغات الأخرى، الكلمة الأساسية يمتد يتم استخدامه لجعل فئة واحدة ترث من فئة أخرى.
يبدو الهيكل عادةً كما يلي:
class ChildClass extends ParentClass {
// child class code
}
وهذا يعني ذلك فئة الطفل يتلقى خصائص وأساليب الوصول إليها ParentClass. يمكن لـ child class بعد ذلك إضافة سلوك جديد أو تخصيص السلوك الموروث عند الحاجة.
على الرغم من أن بناء الجملة الدقيق قد يتغير بين لغات البرمجة، إلا أن المفهوم هو نفسه: الوراثة تخلق علاقة بين فئة عامة وفئة أكثر تحديدًا.
إعادة استخدام الكود مع الوراثة
إحدى الفوائد الرئيسية للميراث هي إعادة استخدام الكود. عندما تحتاج فئات متعددة إلى نفس الوظيفة، يمكن وضع هذه الوظيفة في parent class بدلاً من نسخها في كل child class.
على سبيل المثال، في تطبيق ويب، قد تحتاج أنواع مختلفة من المستخدمين إلى تسجيل الدخول أو تسجيل الخروج أو تحديث ملفاتهم الشخصية أو تغيير كلمة المرور الخاصة بهم. يمكن وضع هذه الإجراءات الشائعة في فئة مستخدم عامة. بعد ذلك، يمكن لفئات المسؤول، والعملاء، والمؤلف، والمحرر أن ترث من المستخدم وتضيف ميزاتها الفريدة.
يقلل هذا الأسلوب من الازدواجية ويجعل تحديث التطبيق أسهل. إذا تغير منطق تسجيل الدخول، فيمكن للمطور تحديثه في فئة المستخدم بدلاً من تحرير كل فئة متعلقة بالمستخدم بشكل منclass.
تجاوز الأسلوب
لا يسمح الوراثة للفصول الفرعية بإعادة استخدام الأساليب فقط. كما يسمح لهم بتخصيص السلوك. وهذا ما يسمى تجاوز الأسلوب.
يحدث تجاوز الطريقة عندما يقوم child class بتعريف طريقة بنفس اسم الطريقة الموجودة في parent class. يستبدل الإصدار الفرعي أو يخصص الإصدار الأصلي لذلك child class المحدد.
مثال:
class User {
public function getRole() {
return "User";
}
}
class Admin extends User {
public function getRole() {
return "Admin";
}
}
هنا، تتجاوز فئة المسؤول طريقة getRole. يقوم كائن المستخدم العادي بإرجاع المستخدم، بينما يقوم كائن المسؤول بإرجاع المسؤول. يسمح هذا للكائنات المختلفة بالاستجابة بشكل مختلف مع الاستمرار في مشاركة بنية مشتركة.
استدعاء طرق الوالدين
في بعض الأحيان، يحتاج child class إلى تخصيص طريقة ما ولكنه لا يزال يستخدم جزءًا من الطريقة الأصلية. تسمح العديد من لغات البرمجة لـ child class باستدعاء الإصدار الأصلي للطريقة.
في PHP، يمكن القيام بذلك باستخدام parent::. على سبيل المثال:
class User {
public function getInfo() {
return "Basic user information";
}
}
class Admin extends User {
public function getInfo() {
return parent::getInfo() . " with admin permissions";
}
}
في هذا المثال، لا تتجاهل فئة المسؤول الطريقة الأصلية بشكل كامل. يستخدم طريقة getInfo الأصلية ويضيف معلومات إضافية. يكون هذا مفيدًا عندما يحتاج child class إلى توسيع السلوك الحالي بدلاً من استبداله بالكامل.
معدّلات الوصول والوراثة
تتحكم معدّلات الوصول في الخصائص والأساليب التي يمكن الوصول إليها من خارج class أو من classes الفرعية. معدّلات الوصول الأكثر شيوعًا هي عام, محمي، و خاص.
عام يمكن عادةً الوصول إلى الأعضاء من أي مكان.
محمي يمكن عادةً الوصول إلى الأعضاء داخل الclass وداخل الفصول الفرعية.
خاص يمكن عادةً الوصول إلى الأعضاء فقط داخل الclass الذي تم تعريفهم فيه.
في الوراثة، يكون الأعضاء المحميون مفيدًا بشكل خاص لأنهم يسمحون للفئات الفرعية باستخدام بيانات الوالدين الداخلية دون جعل تلك البيانات عامة بالكامل للعالم الخارجي.
الأعضاء الخاصون غير متاحين مباشرة لفصول الأطفال بالعديد من اللغات. يساعد هذا في حماية تفاصيل التنفيذ الداخلي ويدعم encapsulation.
أنواع الوراثة
تدعم لغات البرمجة المختلفة أنواعًا مختلفة من الوراثة. النوع الاكثر شيوعا هو ميراث واحد، حيث يرث واحد child class من واحد parent class.
بعض أنواع الوراثة الشائعة تشمل:
الوراثة الفردي: واحد child class يرث من واحد parent class.
الوراثة متعدد المستويات: يرث الclass من child class، مما يؤدي إلى إنشاء سلسلة من الوراثة.
الوراثة الهرمي: ترث فئات فرعية متعددة من نفس parent class.
الوراثة المتعدد: يرث class واحد من أكثر من parent class. وهذا غير مدعوم مباشرة في بعض اللغات مثل PHP وفئات Java.
حتى عندما لا يتم دعم الوراثة المتعددة بشكل مباشر، قد توفر اللغات بدائل مثل interfaces أو السمات. تساعد هذه الأدوات في مشاركة السلوك مع تجنب بعض تعقيدات الوراثة المتعدد.
الوراثة مقابل التكوين
الوراثة مفيد، ولكن لا ينبغي استخدامه في كل علاقة. السؤال الشائع في تصميم البرمجيات هو ما إذا كان سيتم استخدام الوراثة أو التركيب.
يمثل الوراثة هو-أ علاقة. على سبيل المثال، المشرف هو المستخدم، والسيارة هي مركبة. التركيبة تمثل أ لديه أ علاقة. على سبيل المثال، السيارة لديها محرك، والمستخدم لديه ملف تعريف.
إذا كانت العلاقة واضحة، فقد يكون الوراثة مناسبًا. إذا كانت العلاقة مكونة من جزأين، فعادةً ما يكون التكوين هو الخيار الأفضل. إن استخدام الوراثة بشكل غير صحيح يمكن أن يجعل فهم النظام أكثر صعوبة ويصعب تغييره لاحقًا.
مثال في العالم الحقيقي
تخيل منصة التعلم عبر الإنترنت. قد يحتوي النظام الأساسي على أنواع حسابات مختلفة مثل حساب الطالب والمدرس والمسؤول. يتشارك كل منهم معلومات الحساب الأساسية، مثل الاسم والبريد الإلكتروني وكلمة المرور وسلوك تسجيل الدخول.
يمكن أن يحتوي parent class المسمى "الحساب" على البيانات المشتركة والطرق الشائعة. ثم يمكن للطالب والمدرس والمسؤول أن يرثوا من الحساب. يمكن لكل child class إضافة سلوكه الخاص:
يمكن للطالب التسجيل في الدورات وتقديم الواجبات.
يمكن للمدرس إنشاء الدروس ومراجعة التقديمات.
يمكن للمسؤول إدارة المستخدمين والتحكم في إعدادات النظام الأساسي.
تحافظ هذه البنية على المنطق المشترك في مكان واحد مع السماح لكل نوع حساب بأن يكون له مسؤولياته الخاصة.
فوائد الوراثة
يوفر الوراثة العديد من الفوائد المهمة في البرمجة كائنية التوجه:
فهو يقلل من تكرار الكود عن طريق نقل المنطق المشترك إلى parent class.
يعمل على تحسين قابلية الصيانة لأنه يمكن تحديث السلوك الشائع في مكان واحد.
أنه يخلق علاقة واضحة بين الطبقات العامة والخاصة.
وهو يدعم تجاوز الطريقة، مما يسمح للفصول الفرعية بتخصيص السلوك.
يساعد في بناء هياكل برمجية منظمة وقابلة للتطوير.
هذه الفوائد تجعل الوراثة مفيدة في العديد من مشاريع البرمجيات الحقيقية، خاصة عندما تشترك عدة فئات في السلوك المشترك.
الأخطاء الشائعة عند استخدام الوراثة
على الرغم من أن الوراثة قوي، إلا أن المبتدئين غالبًا ما يستخدمونه كثيرًا أو يستخدمونه في الأماكن الخاطئة. أحد الأخطاء الشائعة هو إنشاء علاقات وراثة فقط لإعادة استخدام الكود، حتى عندما لا تكون classes مرتبطة منطقيًا.
خطأ آخر هو إنشاء سلاسل ميراث عميقة جدًا. عندما يرث class من فئة أخرى، والذي يرث من فئة أخرى، وما إلى ذلك، قد يصبح من الصعب متابعة الكود. يمكن أن يؤدي الوراثة العميق إلى جعل عملية التصحيح والصيانة أكثر صعوبة.
الخطأ الثالث هو وضع الكثير من المنطق في parent class. إذا أصبح parent class كبيرًا جدًا، فقد ترث classes الفرعية سلوكًا لا تحتاجه حقًا. وهذا يمكن أن يجعل التصميم أقل نظافة وأقل مرونة.
أفضل الممارسات لاستخدام الوراثة
لاستخدام الوراثة بشكل فعال، يجب على المطورين تطبيقه بعناية وفقط عندما تكون العلاقة بين classes واضحة.
تتضمن أفضل الممارسات المفيدة ما يلي:
استخدم الوراثة عندما تكون هناك علاقة حقيقية.
اجعل دروس أولياء الأمور تركز على السلوك المشترك فقط.
تجنب سلاسل الوراثة العميقة جدًا.
استخدم الأعضاء المحميين بعناية وتجنب الكشف عن الكثير من المنطق الداخلي.
تفضل التركيب عندما تكون العلاقة has-a بدلاً من is-a.
استخدم interfaces عندما تحتاج classes المختلفة إلى اتباع نفس العقد دون مشاركة نفس parent class.
يساعد اتباع هذه الممارسات المطورين على الاستفادة من الوراثة دون خلق تعقيدات غير ضرورية.
الوراثة في الأطر الحديثة
يتم استخدام الوراثة في العديد من أطر البرمجة الحديثة. في تطوير الويب، غالبًا ما يقوم المطورون بتوسيع فئات وحدة التحكم الأساسية أو فئات النماذج أو فئات الخدمة. على سبيل المثال، قد ترث وحدة التحكم سلوك معالجة الطلب المشترك من وحدة التحكم الأساسية.
في أطر عمل PHP مثل Laravel وSymfony، يمكن أن يظهر الوراثة في وحدات التحكم والنماذج وفئات النماذج وفئات الأوامر وفئات الاختبار. ومع ذلك، تستخدم الأطر الحديثة أيضًا التركيب، interfaces، والسمات، وDependency Injection لتجنب الإفراط في استخدام الوراثة.
وهذا يعني أن فهم الوراثة أمر مهم، ولكن يجب على المطورين أيضًا أن يتعلموا متى لا يستخدمونه. يعتمد التصميم الجيد للبرامج على اختيار الأداة المناسبة للمشكلة.
خاتمة
الوراثة هو المبدأ الأساسي لـ البرمجة كائنية التوجه. يسمح للفصول الفرعية بإعادة استخدام وتوسيع خصائص وأساليب classes الأصلية. يساعد هذا في تقليل الازدواجية وتنظيم classes ذات الصلة وإنشاء هياكل برمجية أكثر نظافة.
ومع ذلك، ينبغي استخدام الوراثة بعناية. إنه يعمل بشكل أفضل عندما تكون هناك علاقة واضحة بين الطبقات. عند استخدامه بشكل صحيح، يمكن أن يجعل الوراثة الكود أسهل في الصيانة، وأسهل في التوسيع، وأسهل في الفهم.
بالنسبة للمبتدئين، يعد الوراثة خطوة أساسية نحو فهم موضوعات OOP الأكثر تقدمًا مثل polymorphism، وabstraction، وinterfaces، وأنماط التصميم. يوفر إتقان الوراثة أساسًا قويًا لكتابة كود احترافية موجهة للكائنات.

