تعدد الأشكال polymorphism
تعدد الأشكال ( polymorphism ) المقصود بمصطلح بوليمورفيزم هي الطرق المتاحة للوصول إلى دوال و متغيرات الكلاس. نحن تعلمنا في الدروس السابقة على شكل من اشكال الوصول إلى متغيرات و دوال الكلاس. و هو إنشاء كائن من نفس إسم الكلاس حتى تستطيع الوصول لمتغيرات و دوال الكلاس. و تعلّمنا شكل آخر و هو أننا نستطيع الوصول لمتغيرات و دوال الكلاس الأب بعد الوراثة بواسطة. إنشاء كائن من الكلاس الإبن للوصول لمتغيرات و دوال الكلاس الأب و هذا شكل آخر من الأشكال.
كيف يستطيع الكائن المشتق من الكلاس الأب الوصول إلى متغيرات و دوال الكلاس الإبن؟.
يستطيع الكلاس الأب الوصول إلى دوال و متغيرات الإبن في حالة واحدة فقط و هي تطبيق مبدأ Override.
قبل أن نتكلم عن مبدأ Override ماذا نستفيد من هذا الشكل ولماذا نجعل الكائن المشتق من الكلاس الأب أن يصل إلى متغيرات و دوال الكلاس الإبن؟. يلجأ الكثير في هذا لمبدا Override حتى يستطيع الكائن المشتق من الوصول لكلاسات الأبناء من أجل إختصار الكائنات. يعني بدل عندما يكون لدينا ثلاث كلاسات و كل كلاس ورث من كلاس واحد فبدل من أن نقوم. بإنشاء ثلاث كائنات نستطيع عن طريق مبدأ Override أن ننشئ كائن واحد من الكلاس الأب.
ونستطيع الوصول لمتغيرات و دوال الإبن و لكن بشرط أن تكون هذه المتغيرات تطبق. مبدأ Override حتى يستطيع الكائن المشتق من الأب الوصول إلى هذه الدوال و المتغيرات. وقلنا أننا نستفيد من هذه الطريقة في التقليل من عدد الكائنات لأننا كلما أنشانا كائن يعني أننا نحجز مكان في الذاكرة. و كلما زاد عدد الكائنات كلما كان البرنامج ابطأ و لهذا السبب نلجأ للتخفيف من هذه المشكلة عبر Override.
مفهوم Override في جافا
هو أن يكون لدينا دالة معرّفة في اكثر من كلاس بنفس الإسم و نفس الهيكلية أو أن يكون لدينا متغير. معرّف بأكثر من كلاس بنفس الإسم و نفس النوع لكن بشرط أن تكون معرّفة في الكلاس الأب. هنا نقول أننا طبقنا مبدأ Override و هو أن نقوم بإنشاء دالة في الكلاس الأب و نقوم بإنشاءها بنفس. الإسم و نفس الهيكلية في بقية الكلاسات الأبن حتى يستطيع الأب الوصول إلى هذه المتغيرات و الدوال. و ايضاً نستفيد من Override عندما يكون لدينا دالتين بنفس الإسم و نفس الهيكلية تطبق. مبدأ Override و هذا يعني أننا نحجز مكان واحد من الذاكرة و لا نحجز اكثر من مكان.
هدف البرمجة الكائنية الموجهة oop هو التقليل من حجم الذاكرة و التسريع من عمل البرنامج و هذا الدرس من أهم الدروس الذي يطبق هذا المبدأ. سوف نتعلم في هذا الدرس على مثال بسيط كيف يصل الكلاس الأب إلى دوال و متغيرات الكلاس الإبن. و سنتناول موضوع موسّع عن كيفية الفائدة من أن يصل الكلاس الأب إلى الكلاس الإبن.
مثال 1
package poly; class A { int x; void print () { System.out.println("A"); } } class B extends A { int x; void print () { System.out.println("A"); } } public class Poly{ public static void main(String []args){ A ob=new A (); ob.x=9; ob.print(); A ob1=new B (); ob1.print(); ob1.x=8; } }
كان لدينا كلاس إسمه كلاس A و هو سيكون الأب و لديه متغير إسمه x و لدينا كلاس آخر يرث. من الكلاس A و لديه متغير بنفس الإسم الموجود في الكلاس. الأب إسمه int x هنا طبقنا مبدأ Override و بهذه الطريقة سوف يستطيع الكلاس الأب أن يصل للكلاس الإبن. وفي البرنامج الرئيسي أنشانا كائن من الكلاس الأب إسمه ob و قلنا أنه يساوي new A نلاحظ أنه اخذنا نسخة من الكلاس الأب. و قلنا ob.x=9 و السؤال هنا ما هو x الذي خزننا به القيمة 9 هل هو تابع للأب أو الإبن؟ لأنه نفس الإسم موجود في الأب و الإبن.
و الجواب طالما قلنا أن الكائن المشتق يساوي new A فهذا يعني أن x المقصود بها خاصة بالكلاس الأب A. و قمنا بإشتقاق كائن ob1 ثم قلنا أنه يساوي new B الآن هنا أشرنا إلى الكلاس الإبن و الكائن كان مشتق من الأب و لكنه يُشير إلى الإبن. ثم قلنا ob1.x=8 هنا ستكون x الخاصة بالكلاس B لأن الكائن ob1 يشير للكلاس الإبن و بهذه الطريقة إستطعنا بواسطة الكلاس الأب أن نصل لمتغيرات و دوال الكلاس الإبن.
عند تشغيل الكود السابق سنحصل على النتيجة الآتية:
A A
مثال 2
package poly; class A { int x; void print() { System.out.println("I am parrent") } } class B extends A { int x; int y; void print() { System.out.println("I am child") } } public class Poly{ public static void main(String []args){ A ob1=new A(); ob1.x=10; ob1.print(); A ob2=new B (); ob2.x=7; ob2.print(); } } >
لدينا كلاس أب إسمه A و به متغيرات و دالة و ورث منه إبن إسمه class B لكن في هذا الإبن كان. به متغير زيادة عن أبيه و هو int y و هذا المتغير لن يطبق مبدأ Override لأنه لا يوجد مثله في الأب. و من ثم دخلنا للبرنامج الرئيسي إشتقينا كائن من الكلاس الأب و هو ob1 ثم قلنا أن ob1.x=10 و هذه هي الخاصة بالكلاس الأب. ثم طبعناه عبر print و بعدها وضعنا قيمة للكلاس الإبن ob2.x=7 و طبعناها.
مثال 3 الفائدة الربحية
package branch; class Bank { double profet(double pay) { return pay*0.4; } } class Branch1 extends Bank { double profet(double pay) { return pay*0.3; } } class Branch2 extends Bank { double profet(double pay) { return pay*0.2; } } public class Branch{ public static void main(String []args){ Bank A=new Bank(); System.out.println(A.profet(1000); A=new Branch1(); System.out.println(A.profet(1000); A=new Branch2(); System.out.println(A.profet(1000); } }
اعتبرنا أنه لدينا بنك و أنشأنا كلاس أب بإسم Bank حيث سنعتبره الفرع الرئيسي و به كانت دالة من نوع double تحسب قيمة المبلغ المدفوع و إرجاع مقدار الربح 0.4. و كان هناك فرع آخر لهذا البنك و هو الكلاس الإبن Branch1 ورث من الكلاس الأب و مقدار الربح هنا هو 0.3. و كان هناك فرع آخر و هو الكلاس Branch2 ورث من الكلاس الأب و مقدار الربح به هو 0.2. ثم قمنا بالدخول للبرنامج الرئيسي اشتقينا كائن من الكلاس الأب و طباعة حساب الفائدة من الكلاس الأب 1000 و نفس الأمر كان على الأبناء الإثنين.