تعدد الأشكال 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 و نفس الأمر كان على الأبناء الإثنين.
