الوراثة (البرمجة الكائنية التوجه)
في البرمجة كائنية التوجه ، تُعدّ الوراثة آليةً لإنشاء كائن أو فئة بناءً على كائن آخر ( وراثة قائمة على النموذج الأولي ) أو فئة أخرى ( وراثة قائمة على الفئات )، مع الحفاظ على نفس التنفيذ . كما تُعرَّف الوراثة بأنها اشتقاق فئات جديدة ( فئات فرعية ) من فئات موجودة، مثل الفئة الأصلية أو الفئة الأساسية ، ثم تشكيلها في تسلسل هرمي من الفئات. في معظم لغات البرمجة كائنية التوجه القائمة على الفئات، مثل C++ ، يكتسب الكائن المُنشأ من خلال الوراثة، والذي يُسمى "الكائن الابن"، جميع خصائص وسلوكيات "الكائن الأصل"، باستثناء: الدوال البانية ، والدوال الهدامة، والمعاملات المُحمَّلة بشكل زائد ، ودوال الصداقة الخاصة بالفئة الأساسية. تُمكّن الوراثة المبرمجين من إنشاء فئات مبنية على فئات موجودة، [ 1 ] وتحديد تنفيذ جديد مع الحفاظ على نفس السلوكيات ( تحقيق واجهة )، وإعادة استخدام التعليمات البرمجية، وتوسيع البرامج الأصلية بشكل مستقل عبر الفئات والواجهات العامة . تُؤدي علاقات الكائنات أو الفئات من خلال الوراثة إلى إنشاء رسم بياني موجه غير دوري .
يُطلق على الصنف الموروث اسم الصنف الفرعي للصنف الأب أو الصنف الأصل. يُستخدم مصطلح الوراثة بشكل عام في كلٍ من البرمجة القائمة على الأصناف والبرمجة القائمة على النماذج الأولية، ولكن في الاستخدام الدقيق، يُخصص المصطلح للبرمجة القائمة على الأصناف (حيث يرث صنف من آخر)، بينما تُسمى التقنية المقابلة في البرمجة القائمة على النماذج الأولية بالتفويض (حيث يُفوض كائن إلى آخر). يمكن تحديد أنماط الوراثة المُعدِّلة للأصناف مسبقًا وفقًا لمعلمات واجهة الشبكة البسيطة، بحيث يتم الحفاظ على التوافق بين اللغات. [ 2 ] [ 3 ]
لا ينبغي الخلط بين الوراثة والتصنيف الفرعي . [ 4 ] [ 5 ] في بعض اللغات، وخاصة لغات البرمجة الكائنية التوجه ذات الكتابة الثابتة والقائمة على الأصناف، مثل C++ و C# وJava و Scala ، تتفق الوراثة والتصنيف الفرعي، بينما تختلفان في لغات أخرى. بشكل عام، يُنشئ التصنيف الفرعي علاقة "هو نوع من" ، بينما تعيد الوراثة استخدام التنفيذ فقط وتُنشئ علاقة نحوية، وليست بالضرورة علاقة دلالية (لا تضمن الوراثة التصنيف الفرعي السلوكي). ولتمييز هذين المفهومين، يُشار أحيانًا إلى التصنيف الفرعي باسم وراثة الواجهة (دون الإشارة إلى أن تخصيص متغيرات النوع يُنشئ أيضًا علاقة تصنيف فرعي)، بينما تُعرف الوراثة كما هي مُعرّفة هنا باسم وراثة التنفيذ أو وراثة الكود . [ 6 ] ومع ذلك، تُعد الوراثة آلية شائعة الاستخدام لإنشاء علاقات التصنيف الفرعي. [ 7 ]
يُقارن التوريث بتركيب الكائنات ، حيث يحتوي كائن ما على كائن آخر (أو تحتوي كائنات من فئة ما على كائنات من فئة أخرى)؛ انظر: التركيب مقابل التوريث . وعلى عكس علاقة " هو نوع من" في التوريث الفرعي ، يُطبّق التركيب علاقة "يحتوي على" .
من الناحية الرياضية، فإن الوراثة في أي نظام من الفئات تؤدي إلى ترتيب جزئي صارم على مجموعة الفئات في ذلك النظام.
تاريخ
في عام 1966، قدم توني هوار بعض الملاحظات حول السجلات، وتحديدًا فكرة الفئات الفرعية للسجلات، وهي أنواع سجلات ذات خصائص مشتركة ولكنها تتميز بعلامة متغيرة وحقول خاصة بتلك العلامة. [ 8 ] وتأثرًا بذلك، قدم أولي-يوهان دال وكريستين نيغارد في عام 1967 تصميمًا يسمح بتحديد كائنات تنتمي إلى فئات مختلفة ولكنها تشترك في خصائص مشتركة. جُمعت الخصائص المشتركة في فئة أساسية، ويمكن لكل فئة أساسية أن تحتوي بدورها على فئة أساسية أخرى. وبالتالي، كانت قيم الفئة الفرعية عبارة عن كائنات مركبة، تتكون من عدد من الأجزاء البادئة التي تنتمي إلى فئات أساسية مختلفة، بالإضافة إلى جزء رئيسي ينتمي إلى الفئة الفرعية. وقد جُمعت هذه الأجزاء معًا. [ 9 ] ويمكن الوصول إلى سمات الكائن المركب باستخدام تدوين النقطة. وقد اعتُمدت هذه الفكرة لأول مرة في لغة البرمجة سيمولا 67. [ 10 ] ثم انتشرت الفكرة إلى لغات أخرى مثل سمول توك ، وسي++ ، وجافا ، وبايثون ، وغيرها الكثير.
الأنواع


توجد أنواع مختلفة من الوراثة، تعتمد على النموذج ولغة محددة. [ 11 ]
- الميراث الفردي
- حيث ترث الفئات الفرعية خصائص فئة أصلية واحدة. تكتسب الفئة خصائص فئة أخرى.
- الوراثة المتعددة
- حيث يمكن أن يكون للفئة الواحدة أكثر من فئة أساسية واحدة وأن ترث الميزات من جميع الفئات الأصلية.
كان يُعتقد على نطاق واسع أن الوراثة المتعددة صعبة التنفيذ بكفاءة. فعلى سبيل المثال، في ملخص للغة C++ في كتابه عن Objective C ، ادعى براد كوكس أن إضافة الوراثة المتعددة إلى C++ أمر مستحيل. ولذلك، بدت الوراثة المتعددة أكثر صعوبة. وبما أنني كنت قد فكرت في الوراثة المتعددة منذ عام 1982، ووجدت أسلوبًا بسيطًا وفعالًا لتنفيذها في عام 1984، لم أستطع مقاومة هذا التحدي. وأظن أن هذه هي الحالة الوحيدة التي أثرت فيها الموضة على تسلسل الأحداث. [ 12 ]
- الوراثة متعددة المستويات
- حيث يتم توريث فئة فرعية من فئة فرعية أخرى. ليس من غير المألوف أن يتم اشتقاق فئة من فئة مشتقة أخرى كما هو موضح في الشكل "الوراثة متعددة المستويات".

الوراثة متعددة المستويات - تُعدّ الفئة A فئة أساسية للفئة المشتقة B ، والتي بدورها تُعدّ فئة أساسية للفئة المشتقة C. تُعرف الفئة B بالفئة الأساسية الوسيطة لأنها تُوفّر رابطًا للوراثة بين A و C. تُعرف سلسلة ABC بمسار الوراثة .
- يتم تعريف فئة مشتقة ذات وراثة متعددة المستويات على النحو التالي:
// فئة تنفيذ بلغة C++، الفئة A { ... }; // الفئة الأساسية، الفئة B : عامة A { ... }; // B مشتقة من A، الفئة C : عامة B { ... }; // C مشتقة من B
- يمكن توسيع هذه العملية لتشمل أي عدد من المستويات.
- الوراثة الهرمية
- هنا، تعمل فئة واحدة كفئة أساسية لأكثر من فئة فرعية. على سبيل المثال، يمكن أن يكون للفئة الأصلية A فئتان فرعيتان B وC. الفئة الأصلية لكل من B وC هي A، لكن B وC فئتان فرعيتان منفصلتان.
- الوراثة الهجينة
- الوراثة الهجينة هي مزيج من نوعين أو أكثر من أنواع الوراثة المذكورة أعلاه. مثال على ذلك هو عندما يكون للصنف A صنف فرعي B، والذي بدوره يحتوي على صنفين فرعيين، C وD. هذا مزيج من الوراثة متعددة المستويات والوراثة الهرمية.
الفئات الفرعية والفئات الرئيسية
الفئات الفرعية ، أو الفئات المشتقة ، أو الفئات الوارثة ، أو الفئات الابنة، هي فئات مشتقة معيارية ترث كيانًا لغويًا واحدًا أو أكثر من فئة أخرى أو أكثر (تُسمى الفئة الأصلية ، أو الفئات الأساسية ، أو الفئات الأبوية ). تختلف دلالات وراثة الفئات من لغة إلى أخرى، ولكن عادةً ما ترث الفئة الفرعية تلقائيًا متغيرات النسخة ووظائف الأعضاء من فئاتها الأصلية.
في لغة C++، يكون الشكل العام لتعريف فئة مشتقة كما يلي: [ 13 ]
class SubClass : visibility SuperClass { // أعضاء الفئة الفرعية };تشير النقطتان الرأسيتان إلى أن الفئة الفرعية ترث من الفئة الأصلية. مُعدِّل الرؤية اختياري، وإذا وُجد، فقد يكون خاصًا أو عامًا . الرؤية الافتراضية (في حال عدم وجود مُعدِّل) هي خاصة . تُحدد الرؤية ما إذا كانت خصائص الفئة الأساسية مُشتقة بشكل خاص أو عام .
لاحظ أنه في بعض اللغات الأخرى مثل جافا وسي شارب، لا يوجد مُعدِّل رؤية للوراثة:
// بدون مُعدِّل رؤية // مُكافئ لـ public SuperClass في لغة C++ class SubClass extends SuperClass { // أعضاء الفئة الفرعية }تدعم بعض اللغات أيضًا وراثة بنيات أخرى. على سبيل المثال، في لغة إيفل ، تُورَث العقود التي تُحدد مواصفات فئة ما إلى الفئات الوريثة. تُنشئ الفئة الأصلية واجهة مشتركة ووظائف أساسية، يمكن للفئات الفرعية المتخصصة وراثتها وتعديلها واستكمالها. يُعتبر البرنامج الذي ترثه الفئة الفرعية مُعاد استخدامه فيها. قد يُشير مرجع إلى مثيل فئة ما في الواقع إلى إحدى فئاتها الفرعية. من المستحيل التنبؤ بالفئة الفعلية للكائن المُشار إليه في وقت الترجمة . تُستخدم واجهة موحدة لاستدعاء الدوال الأعضاء لكائنات من عدد من الفئات المختلفة. يمكن للفئات الفرعية استبدال دوال الفئة الأصلية بدوال جديدة تمامًا يجب أن تشترك في نفس توقيع الدالة .
الفئات غير القابلة للتوريث
في بعض لغات البرمجة، يُمكن تعريف فئة على أنها غير قابلة للتوريث بإضافة مُعدِّلات مُحدَّدة إلى تعريفها. ومن الأمثلة على ذلك الكلمة finalالمفتاحية `const` في Java و C++11 وما بعدها، أو الكلمة sealedالمفتاحية `const` في C#. تُضاف هذه المُعدِّلات إلى تعريف الفئة قبل الكلمة classالمفتاحية `const` وتعريف مُعرِّف الفئة. تُقيِّد هذه الفئات غير القابلة للتوريث إمكانية إعادة استخدامها ، خاصةً عندما لا يملك المُطوِّرون سوى الملفات الثنائية المُجمَّعة مُسبقًا وليس شفرة المصدر .
لا تحتوي الفئة غير القابلة للتوريث على فئات فرعية، لذا يُمكن استنتاج أن المراجع أو المؤشرات إلى كائنات تلك الفئة تُشير في الواقع إلى مثيلات من تلك الفئة نفسها، وليس إلى مثيلات من فئات فرعية (فهي غير موجودة) أو مثيلات من فئات أصلية (لأن تحويل نوع مرجعي إلى نوع أعلى يُخالف نظام الأنواع). ولأن النوع الدقيق للكائن المُشار إليه معروف قبل التنفيذ، يُمكن استخدام الربط المُبكر (المعروف أيضًا بالتوزيع الثابت ) بدلًا من الربط المُتأخر (المعروف أيضًا بالتوزيع الديناميكي )، الذي يتطلب بحثًا واحدًا أو أكثر في جدول الأساليب الافتراضية، وذلك بحسب ما إذا كانت لغة البرمجة المُستخدمة تدعم الوراثة المتعددة أو الوراثة الفردية فقط.
الأساليب غير القابلة للتجاوز
كما هو الحال مع الفئات التي قد لا تكون قابلة للتوريث، قد تحتوي تعريفات الدوال على مُعدِّلات تمنع إعادة تعريف الدالة (أي استبدالها بدالة جديدة بنفس الاسم ونوع التوقيع في فئة فرعية). الدالة الخاصة غير قابلة لإعادة التعريف ببساطة لأنها غير متاحة للفئات الأخرى غير الفئة التي تُعد دالة عضوية فيها (مع أن هذا لا ينطبق على لغة C++). لا يمكن إعادة تعريف أي finalدالة في Java أو sealedC# أو أي frozenميزة في Eiffel.
الأساليب الافتراضية
إذا كانت دالة الفئة الأصلية دالة افتراضية ، فسيتم استدعاء هذه الدالة ديناميكيًا . تتطلب بعض اللغات تعريف الدالة تحديدًا على أنها افتراضية (مثل C++)، بينما في لغات أخرى، تكون جميع الدوال افتراضية (مثل Java). أما استدعاء الدالة غير الافتراضية فيتم دائمًا بشكل ثابت (أي يتم تحديد عنوان استدعاء الدالة في وقت الترجمة). يُعدّ الاستدعاء الثابت أسرع من الاستدعاء الديناميكي، كما يسمح بإجراء تحسينات مثل التوسيع المضمن .
ظهور الأعضاء الموروثين
يوضح الجدول التالي المتغيرات والوظائف التي يتم توريثها اعتمادًا على مستوى الرؤية المحدد عند اشتقاق الفئة، باستخدام المصطلحات التي وضعتها لغة C++. [ 14 ]
| رؤية الفئة الأساسية | رؤية الفئة المشتقة | ||
|---|---|---|---|
| الاشتقاق الخاص | الاشتقاق المحمي | الاشتقاق العام | |
|
|
|
|
التطبيقات
تُستخدم الوراثة لربط فئتين أو أكثر ببعضهما البعض.
تجاوز

تسمح العديد من لغات البرمجة كائنية التوجه للفئة أو الكائن باستبدال تنفيذ جانبٍ ما - عادةً سلوك - ورثه. تُسمى هذه العملية "التجاوز" . يُثير التجاوز تعقيدًا: أي نسخة من السلوك تستخدمها نسخة من الفئة الموروثة - النسخة الخاصة بها، أم النسخة من الفئة الأصلية (الأساسية)؟ تختلف الإجابة بين لغات البرمجة، وتوفر بعض اللغات إمكانية الإشارة إلى عدم تجاوز سلوك معين، وأن يتصرف كما هو مُعرّف في الفئة الأساسية. على سبيل المثال، في لغة C#، لا يمكن تجاوز الطريقة أو الخاصية الأساسية في فئة فرعية إلا إذا كانت مُعلّمة بالمُعدِّل virtual أو abstract أو override، بينما في لغات برمجة مثل Java، يمكن استدعاء طرق مختلفة لتجاوز طرق أخرى. [ 15 ] يُعد إخفاء الكود الموروث بديلاً عن التجاوز .
إعادة استخدام الكود
يُعدّ التوريث التنفيذي آليةً تُتيح للفئة الفرعية إعادة استخدام التعليمات البرمجية الموجودة في الفئة الأساسية. تحتفظ الفئة الفرعية افتراضيًا بجميع عمليات الفئة الأساسية، ولكن يُمكنها تجاوز بعض أو كل العمليات، واستبدال تنفيذ الفئة الأساسية بتنفيذها الخاص.
في المثال التالي، تقوم الفئات الفرعية SquareSumComputerبتجاوز CubeSumComputerطريقة transform()الفئة الأساسية SumComputer. تتضمن الفئة الأساسية عمليات لحساب مجموع مربعات عددين صحيحين. تعيد الفئة الفرعية استخدام جميع وظائف الفئة الأساسية باستثناء عملية تحويل العدد إلى مربعه، حيث تستبدلها بعملية تحويل العدد إلى مربعه ومكعبه على التوالي. وبالتالي، تحسب الفئات الفرعية مجموع مربعات/مكعبات عددين صحيحين .
![]()
فيما يلي مثال على لغة جافا.
استيراد java.util.List ؛ استيراد java.util.stream.Collectors ؛ استيراد java.util.stream.IntStream ؛فئة مجردة SumComputer { عدد صحيح خاص a ؛ عدد صحيح خاص b ؛دالة عامة SumComputer ( عدد صحيح a ، عدد صحيح b ) { this.a = a ; this.b = b ; }// طريقة مجردة يتم تنفيذها بواسطة الفئات الفرعية public abstract int transform ( int x );public List <Integer> inputs ( ) { return IntStream.rangeClosed ( a , b ) .boxed.collect ( Collectors.toList ( ) ) ; }public int compute () { return inputs (). stream () . mapToInt ( this :: transform ) . sum (); } }class SquareSumComputer extends SumComputer { public SquareSumComputer ( int a , int b ) { super ( a , b ); }@Override public int transform ( int x ) { return x * x ; } }class CubeSumComputer extends SumComputer { public CubeSumComputer ( int a , int b ) { super ( a , b ); }@Override public int transform ( int x ) { return x * x * x ; } }في معظم الأوساط، لم يعد استخدام وراثة الأصناف لغرض إعادة استخدام الكود فقط شائعًا. يكمن القلق الرئيسي في أن وراثة التنفيذ لا تضمن إمكانية الاستبدال متعدد الأشكال - فلا يمكن بالضرورة استبدال نسخة من الصنف المُعاد استخدامه بنسخة من الصنف الموروث. يتطلب أسلوب بديل، وهو التفويض الصريح ، جهدًا برمجيًا أكبر، ولكنه يتجنب مشكلة الاستبدال. في لغة C++، يمكن استخدام الوراثة الخاصة كشكل من أشكال وراثة التنفيذ دون إمكانية الاستبدال. بينما تمثل الوراثة العامة علاقة "هو نوع من" ويمثل التفويض علاقة "يحتوي على"، يمكن اعتبار الوراثة الخاصة (والمحمية) علاقة "يتم تنفيذها من خلال". [ 16 ]
يُستخدم التوريث بشكل شائع لضمان احتفاظ الأصناف بواجهة مشتركة محددة؛ أي أنها تُنفذ نفس الأساليب. يمكن أن يكون الصنف الأب مزيجًا من العمليات المُنفذة والعمليات التي سيتم تنفيذها في الأصناف الأبناء. غالبًا، لا يوجد تغيير في الواجهة بين النوع الأب والنوع الأبناء - يُنفذ الصنف الابن السلوك الموصوف بدلاً من الصنف الأب. [ 17 ]
الوراثة مقابل التصنيف الفرعي
الوراثة مشابهة للتصنيف الفرعي ولكنها تختلف عنه . [ 4 ] يُمكّن التصنيف الفرعي من استبدال نوع معين بنوع آخر أو تجريد آخر، ويُقال إنه يُنشئ علاقة "هو نوع" بين النوع الفرعي وتجريد موجود، إما ضمنيًا أو صراحةً، اعتمادًا على دعم اللغة. يمكن التعبير عن هذه العلاقة صراحةً عبر الوراثة في اللغات التي تدعم الوراثة كآلية للتصنيف الفرعي. على سبيل المثال، يُنشئ كود C++ التالي علاقة وراثة صريحة بين الفئتين B و A ، حيث B هي فئة فرعية ونوع فرعي من A ، ويمكن استخدامها كـ A أينما تم تحديد B (عبر مرجع أو مؤشر أو الكائن نفسه).
class A { public : void methodOfA () const { // ... } };class B : public A { public : void methodOfB () const { // ... } };void functionOnA ( const A & a ) { a . methodOfA (); }int main () { B b ; functionOnA ( b ); // يمكن استبدال b بـ A. }في لغات البرمجة التي لا تدعم الوراثة كآلية للتصنيف الفرعي ، تكون العلاقة بين الفئة الأساسية والفئة المشتقة علاقة بين التطبيقات فقط (آلية لإعادة استخدام الكود)، مقارنةً بالعلاقة بين الأنواع . ولا تستلزم الوراثة، حتى في لغات البرمجة التي تدعمها كآلية للتصنيف الفرعي، بالضرورة تصنيفًا فرعيًا سلوكيًا . فمن الممكن تمامًا اشتقاق فئة يتصرف كائنها بشكل غير صحيح عند استخدامه في سياق يُتوقع فيه استخدام الفئة الأصلية؛ انظر مبدأ استبدال ليسكوف . [ 18 ] (قارن بين الدلالة الضمنية والدلالة الصريحة ). في بعض لغات البرمجة الكائنية التوجه، تتداخل مفاهيم إعادة استخدام الكود والتصنيف الفرعي لأن الطريقة الوحيدة لتعريف نوع فرعي هي تعريف فئة جديدة ترث تطبيق فئة أخرى.
قيود التصميم
إن استخدام الوراثة على نطاق واسع في تصميم البرامج يفرض قيوداً معينة.
على سبيل المثال، لنفترض وجود فئة Personتحتوي على اسم الشخص وتاريخ ميلاده وعنوانه ورقم هاتفه. يمكننا تعريف فئة فرعية من فئة "شخص"Student تحتوي على معدله التراكمي والمواد التي درسها، وفئة فرعية أخرى من فئة "شخص " تحتوي على مسمى وظيفته وجهة عمله وراتبه.
عند تحديد هذا التسلسل الهرمي للوراثة، قمنا بالفعل بتحديد بعض القيود، والتي ليس جميعها مرغوبًا فيه:
- الوراثة الأحادية : باستخدام الوراثة الأحادية، يمكن للفئة الفرعية أن ترث من فئة أصلية واحدة فقط. بالعودة إلى المثال السابق،
Personيمكن أن يكون الكائن إما فئة أصليةStudentأو فئة فرعيةEmployee، ولكن ليس كليهما. تُحل هذه المشكلة جزئيًا باستخدام الوراثة المتعددة، حيث يمكن تعريفStudentEmployeeفئة ترث من كلتاStudentالفئتينEmployee. مع ذلك، في معظم التطبيقات، لا يزال بإمكانها الوراثة من كل فئة أصلية مرة واحدة فقط، وبالتالي، لا تدعم الحالات التي يكون فيها للطالب وظيفتان أو يدرس في مؤسستين تعليميتين. يُتيح نموذج الوراثة المتوفر في لغة إيفل إمكانية ذلك من خلال دعم الوراثة المتكررة . - ثابت : يكون التسلسل الهرمي للوراثة للكائن ثابتًا عند إنشاء الكائن واختيار نوعه، ولا يتغير بمرور الوقت. على سبيل المثال، لا يسمح مخطط الوراثة
Studentلكائن ما بأن يصبحEmployeeكائنًا آخر مع الاحتفاظ بحالة فئتهPersonالأصلية. (مع ذلك، يمكن تحقيق هذا السلوك باستخدام نمط المُزخرف ). وقد انتقد البعض الوراثة، بحجة أنها تُقيد المطورين بمعايير التصميم الأصلية. [ 19 ] - الرؤية : عندما يتمكن كود العميل من الوصول إلى كائن ما، فإنه عادةً ما يتمكن من الوصول إلى جميع بيانات الفئة الأصلية لهذا الكائن. حتى لو لم يتم تعريف الفئة الأصلية على أنها عامة، فلا يزال بإمكان العميل تحويل الكائن إلى نوع فئته الأصلية. على سبيل المثال، لا توجد طريقة لإعطاء دالة مؤشرًا إلى
Studentالمعدل التراكمي والسجل الأكاديمي لطالب دون منح تلك الدالة أيضًا إمكانية الوصول إلى جميع البيانات الشخصية المخزنة في الفئة الأصلية للطالبPerson. توفر العديد من اللغات الحديثة، بما في ذلك C++ وJava، مُعدِّل وصول "محمي" يسمح للفئات الفرعية بالوصول إلى البيانات، دون السماح لأي كود خارج سلسلة الوراثة بالوصول إليها.
يُعدّ مبدأ إعادة الاستخدام المركب بديلاً عن الوراثة. تدعم هذه التقنية تعدد الأشكال وإعادة استخدام الكود من خلال فصل السلوكيات عن التسلسل الهرمي للفئات الأساسية، وتضمين فئات سلوكية محددة حسب الحاجة في أي فئة من فئات مجال العمل. يتجنب هذا النهج الطبيعة الثابتة للتسلسل الهرمي للفئات، إذ يسمح بتعديل السلوكيات أثناء التشغيل، ويتيح لفئة واحدة تنفيذ سلوكيات متنوعة، بدلاً من أن تقتصر على سلوكيات فئاتها الأصلية.
القضايا والبدائل
لطالما كان مفهوم وراثة التنفيذ مثيرًا للجدل بين المبرمجين ونظريي البرمجة الكائنية التوجه منذ تسعينيات القرن الماضي على الأقل. ومن بين المنتقدين مؤلفو كتاب " أنماط التصميم" ، الذين يدعون إلى وراثة الواجهات، ويفضلون التركيب على الوراثة . فعلى سبيل المثال، تم اقتراح نمط المُزخرف (كما ذُكر سابقًا ) للتغلب على الطبيعة الثابتة للوراثة بين الأصناف. وكحلٍّ أكثر جوهرية للمشكلة نفسها، تُقدّم البرمجة الموجهة بالأدوار علاقةً مميزة، تُسمى "يلعبها" ، تجمع بين خصائص الوراثة والتركيب في مفهوم جديد.
بحسب ألين هولوب ، تكمن المشكلة الرئيسية في وراثة التنفيذ في أنها تُدخل ترابطًا غير ضروري على شكل "مشكلة الفئة الأساسية الهشة" : [ 6 ] إذ يمكن أن تُسبب التعديلات على تنفيذ الفئة الأساسية تغييرات سلوكية غير مقصودة في الفئات الفرعية. ويُجنّب استخدام الواجهات هذه المشكلة لأنه لا تتم مشاركة أي تنفيذ، بل واجهة برمجة التطبيقات فقط. [ 19 ] وبعبارة أخرى، "تُخلّ الوراثة بمبدأ التغليف ". [ 20 ] وتبرز هذه المشكلة بوضوح في الأنظمة المفتوحة الموجهة للكائنات، مثل الأطر البرمجية ، حيث يُتوقع من كود العميل أن يرث من الفئات التي يوفرها النظام، ثم يُستبدل بها في خوارزمياته. [ 6 ]
يُقال إن جيمس جوسلينج ، مخترع لغة جافا، قد عارض وراثة التنفيذ، مصرحًا بأنه لن يُدرجها لو أعاد تصميم جافا. [ 19 ] ظهرت تصميمات لغات تفصل الوراثة عن التوريث الفرعي (وراثة الواجهات) في وقت مبكر من عام 1990؛ [ 21 ] ومن الأمثلة الحديثة على ذلك لغة البرمجة جو .
قد يؤدي استخدام الوراثة المعقدة، أو الوراثة ضمن تصميم غير ناضج بما فيه الكفاية، إلى مشكلة التذبذب . عندما كانت الوراثة تُستخدم كنهج أساسي لهيكلة البرامج في أواخر التسعينيات، كان المطورون يميلون إلى تقسيم الشيفرة إلى طبقات وراثية أكثر مع ازدياد وظائف النظام. إذا جمع فريق التطوير بين طبقات وراثية متعددة ومبدأ المسؤولية الواحدة، ينتج عن ذلك العديد من الطبقات البرمجية الرقيقة جدًا، حيث تتكون العديد منها من سطر أو سطرين فقط من الشيفرة الفعلية. كثرة الطبقات تجعل عملية تصحيح الأخطاء تحديًا كبيرًا، إذ يصعب تحديد الطبقة التي تحتاج إلى تصحيح.
من المشاكل الأخرى المتعلقة بالوراثة ضرورة تعريف الفئات الفرعية في الكود، مما يعني عدم قدرة مستخدمي البرنامج على إضافة فئات فرعية جديدة أثناء التشغيل. بينما تسمح أنماط تصميم أخرى (مثل نظام الكيان-المكون-الكيان ) لمستخدمي البرنامج بتعريف اختلافات الكيان أثناء التشغيل.
انظر أيضاً
- مشكلة الدائرة والقطع الناقص – مشكلة في البرمجة كائنية التوجه
- الاستدلال القابل للدحض – الاستدلال الذي يكون مقنعًا من الناحية العقلانية، وإن لم يكن صحيحًا من الناحية الاستنتاجية.
- الواجهة (الحوسبة) - الحدود المشتركة بين عناصر نظام الحوسبة
- تجاوز الأساليب – ميزة لغوية في البرمجة الكائنية التوجه
- Mixin – فئة تُستخدم لحقن الطرق
- تعدد الأشكال (علوم الحاسوب) - استخدام واجهة أو رمز واحد فيما يتعلق بأنواع متعددة مختلفة
- البروتوكول – تجريد لفئة صفحات تعرض أوصافًا مختصرة لأهداف إعادة التوجيه
- البرمجة الموجهة نحو الأدوار – نموذج برمجي قائم على الفهم المفاهيمي للكائنات
- السمة (برمجة الحاسوب) - مجموعة من الأساليب التي توسع وظائف فئة معينة
- الوراثة الافتراضية – تقنية في لغة C++
مراجع
- ↑ جونسون، رالف (26 أغسطس 1991). "تصميم الفئات القابلة لإعادة الاستخدام" (ملف PDF) . www.cse.msu.edu .
- ↑ مادسن، أو. إل. (1989). "الفئات الافتراضية: آلية فعّالة في البرمجة كائنية التوجه". وقائع مؤتمر أنظمة ولغات وتطبيقات البرمجة كائنية التوجه - OOPSLA '89 . الصفحات 397-406 . doi : 10.1145/74877.74919 . ISBN 0897913337. S2CID 1104130 .
- ↑ ديفيز، تورك (2021). الأساليب المتقدمة والتعلم العميق في رؤية الحاسوب . إلسيفير ساينس. ص 179-342 .
- 1 2 كوك، ويليام ر.؛ هيل، والتر؛ كانينغ، بيتر س. (1990). الوراثة ليست تنويعًا فرعيًا . وقائع الندوة السابعة عشرة لجمعية ACM SIGPLAN-SIGACT حول مبادئ لغات البرمجة (POPL). الصفحات 125-135 . CiteSeerX 10.1.1.102.8635 . doi : 10.1145/96709.96721 . ISBN 0-89791-343-4.
- ↑ كارديلي، لوكا (1993). البرمجة القائمة على النوع (تقرير فني). شركة ديجيتال إكويبمنت . ص 32-33. تقرير أبحاث SRC رقم 45.
- 1 2 3 ميخايلوف، ليونيد؛ سيكيرينسكي، إميل (1998). دراسة لمشكلة فئة القاعدة الهشة (ملف PDF) . وقائع المؤتمر الأوروبي الثاني عشر حول البرمجة كائنية التوجه (ECOOP). سلسلة محاضرات في علوم الحاسوب. المجلد 1445. سبرينغر. الصفحات 355-382 . doi : 10.1007/BFb0054099 . ISBN 978-3-540-64737-9أُرشف من النسخة الأصلية (PDF) بتاريخ 13 أغسطس 2017. تم الاطلاع عليه بتاريخ 28 أغسطس 2015 .
- ↑ تيمبيرو، إيوان؛ يانغ، هونغ يول؛ نوبل، جيمس (2013). ما يفعله المبرمجون بالوراثة في جافا (ملف PDF) . ECOOP 2013 - البرمجة كائنية التوجه. سلسلة محاضرات في علوم الحاسوب. المجلد 7920. سبرينغر. الصفحات 577-601 . doi : 10.1007/978-3-642-39038-8_24 . ISBN 978-3-642-39038-8.
- ↑ هوار، سي إيه آر (1966). معالجة السجلات (ملف PDF) (تقرير فني). الصفحات 15-16 .
- ↑ دال، أولي-يوهان ؛ نيغارد، كريستين (مايو 1967). تعريفات الفئات والفئات الفرعية (ملف PDF) . مؤتمر IFIP العملي حول لغات المحاكاة. أوسلو: المركز النرويجي للحوسبة.
- ↑ دال، أولي-يوهان (2004). "نشأة البرمجة الكائنية: لغات سيمولا" (ملف PDF) . من البرمجة الكائنية إلى الأساليب الرسمية . سلسلة محاضرات في علوم الحاسوب. المجلد 2635. الصفحات 15-25 . doi : 10.1007/978-3-540-39993-3_3 . ISBN 978-3-540-21366-6.
- ↑ "الوراثة في لغة C++" . www.cs.nmsu.edu . مؤرشف من الأصل بتاريخ 24-09-2023 . تم الاطلاع عليه بتاريخ 16-05-2018 .
- ↑ ستروستروب، بيارن (1994). تصميم وتطور لغة C++ . بيرسون. ص 417. ISBN 9780135229477.
- ↑ شيلدت، هربرت ( 2003). المرجع الكامل للغة سي++ . دار تاتا ماكجرو هيل للنشر. ص 417. ISBN 978-0-07-053246-5.
- ↑ بالاغوروسامي، إي. (2010). البرمجة الكائنية باستخدام لغة C++ . دار نشر تاتا ماكجرو هيل. ص 213. ISBN 978-0-07-066907-9.
- ↑ تجاوز (مرجع C#)
- ↑ "GotW #60: تصميم الفئات الآمنة من الاستثناءات، الجزء 2: الوراثة" . Gotw.ca. تم الاطلاع عليه بتاريخ 15 أغسطس 2012 .
- ^ فينوجوبال، KR؛ بويا، راجكومار (2013). إتقان لغة C++ . تاتا ماكجرو هيل للتعليم الخاص المحدود. ص. 609. ردمك 9781259029943.
- ↑ ميتشل، جون (2002). "10 مفاهيم في لغات البرمجة الكائنية التوجه"مفاهيم في لغات البرمجة . مطبعة جامعة كامبريدج . ص 287. ISBN 978-0-521-78098-8.
- 1 2 3 هولوب، ألين (1 أغسطس 2003). "لماذا التمديد شر؟" . مؤرشف من الأصل في 24 فبراير 2019. تم الاسترجاع في 10 مارس 2015 .
- ↑ سايتر، ليندا م.؛ بالسبيرغ، ينس؛ ليبرهير، كارل ج. (1996). "تطور سلوك الكائنات باستخدام علاقات السياق" . ملاحظات هندسة البرمجيات ACM SIGSOFT . 21 (6): 46. CiteSeerX 10.1.1.36.5053 . doi : 10.1145/250707.239108 .
- ↑ أمريكا، بيير (1991). تصميم لغة برمجة كائنية التوجه مع التنميط الفرعي السلوكي . مدرسة/ورشة عمل REX حول أسس لغات البرمجة كائنية التوجه. سلسلة محاضرات في علوم الحاسوب. المجلد 489. الصفحات 60-90. doi : 10.1007 / BFb0019440 . ISBN 978-3-540-53931-5.
للمزيد من القراءة
- ماير، برتراند (1997). "24. الاستخدام الأمثل للوراثة" (ملف PDF) . بناء البرمجيات الموجهة للكائنات ( الطبعة الثانية). برنتيس هول. الصفحات 809-870 . ISBN 978-0136291558.
- ساموخين، فاديم (2017). "توريث التنفيذ شرٌّ" . هاكر نون . ميديوم.
- الوراثة الفردية في جافا
- الوراثة الهجينة في جافا
- البرمجة الكائنية التوجه
- أنظمة الكتابة
