Inheritance

لو تكلمنا علمياً بهذا الموضوع واردنا تبسيط مفهوم الوراثة سنقول أن تنتقل بعض من صفات الوالدين أو جميعها للطفل ، ونفس الشيء يحدث برمجيا نستطيع إنشاء تصنيف class يرث من تصنيف class أخر .

أولا : مفاهيم متعلقة بالوراثة :-

سنتعرف على طريقة الوراثة برمجيا ولكن بعد توضيح بعض المفاهيم العامة كالتالي :

 

فلنفترض أن لدينا class Person  يحتوي على الاتي : { اسم الشخص – تاريخ الميلاد – الرقم المدني } ، وانشأنا class Employee يرث من class Person  يحتوي على الاتي : { الرقم الوظيفي } ، فهنا class Employee يستطيع الوصول إلى محتويات class Person   من الاسم وتاريخ الميلاد والرقم المدني بالإضافة إلى ما يتضمنه هذا التصنيف من الرقم الوظيفي .

حسناً نكمل الشرح ونلاحظ أن الوظائف أنواع فلدينا المعلم ولدينا المهندس ولدينا الطبيب وغيرها الكثير وجميعهم يرثون من class Employee وبالطبع يا عزيزي بما أنهم يرثون منه وهو بدوره يرث من class Person  فهم يستطيعون الوصول إلى محتويات class Person  أيضاً ، هذا الشيء يشبه كثيرا ما تقدم شرحه في التمهيد فوق بأن الطفل يستطيع أن يرث من والديه ولكن هل فقط والديه ؟ لا أيضا قد يرث من جديه صفات. إذا نحن الأن نعلم أن في الوراثة نستطيع الوصول إلى كافة محتويات class الموروث .


من هو الوارث ومن هو الموروث ؟

الموروث في المثال أعلاه هو class person هو الأب يعتبر ونطلق عليه super ، أما الوارث فهو class Employee ونسميه sub  أي فرعي . وبالطبع المعلم والطبيب والمهندس يعتبرون وارثين ويعتبرون sub  ، والموروث هو class Employee الذي يعد بالنسبة لهم super .


ثانياً : الوراثة في البرمجة :-

التصنيف الأب أو super class لكي نستطيع أن نجعل تصنيف أخر يرث منه لابد من وضع كلمة open عند إنشائه ، مثال :

-: super class

open class person(){

    var name:String? = null
    var id :Int? = null

    fun getInfo(){
        println("The name is :$name your Id is : $id")
    }

    fun getId(id:Int){
        println("your id is :$id")

    }
}

إذا نلاحظ أنه تصنيف عادي قمنا بإنشائه كما تعلمنا ولكن لأن هناك تصنيف أخر سيرث منه فيجب علينا جعله مفتوح ليستطيع الوارث أن يصل لمحتويات هذا التصنيف .

أما بالنسبة للتصنيف الوارث فعلى هذا النحو يتم كتابته :

-: sub class

class Employee(): person()
{
    var idj :Int?=null

    fun printAllData(){
        println("the ID for your job : $idj")
    }
}

عند إنشاء التصنيف نقوم فورا بعملية الوراثة class Employee(): person() نقطتين رأسيتين ومن ثم اسم التصنيف الموروث .

في الدالة الرئيسية :-

نقوم بإنشاء كائن من class Employee وذلك لتوضيح كيف تتم عملية الوراثة :-

نرى أن الكائن المشتق من  class Employee استطاع الوصول إلى محتويات  class Person وهذا الغرض الرئيسي من عملية الوراثة أن الكائن يستطيع الوصول إلى محتويات super class .


ثالثاً : التعامل مع الوسائط الممررة للتصنيف :-

 لو كان class Person ممرر له وسائط  وهذا الشيء طبيعي كما تعرفنا عليه مسبقا عند إنشاء تصنيف ، كيف سنتعامل معه في الوراثة ؟

الجواب كالتالي :

  • نقوم بإنشاء ت التصنيف الموروث او ما نسميه بـ super class ونمرر له وسائط . مثال :-
open class person(id :Int , name :String){

    var id:Int = id
    var name :String = name
            .
            .
            .
}
  • نقوم بإنشاء sub class ونمرر له أيضا نفس الوسائط الذي سيرثها . مثال :-
class Employee(id :Int , name :String) : person(id , name)
{
    .
    .
    .
}

نلاحظ مررنا نفس الوسائط للتصنيف الذي سيرث ومن ثم وضعنا اسم التصنيف الموروث ومررنا المتغيرات بشكل طبيعي بدون تعريف لها أو لنوعها .

حسنا نفس الشيء ينطبق لو كان لدي constructor دالة بناء :-

-: super class

open class person{

    var id:Int? = null
    var name :String? = null

    constructor(id:Int,name:String){

        this.id = id
        this.name=name
    }

}

-: sub class

 class Employee : person
{
    constructor(id:Int,name:String):super(id , name){

        this.id = id
        this.name=name
    }
}

ونلاحظ هنا أننا قمنا باستخدام كلمة super ليتضح لنا أنها keywords في لغة الـ  kotlin ، ونقصد بها هنا الوصول إلى دالة البناء الخاصة بالتصنيف الأب .


رابعا : الفرق بين this و super :-

الفرق بسيط جداً :-

  • نستخدم this في التصنيف نفسه وللتعبير عن محتوياته كما تعلمنا مسبقاً .
  • نستخدم super للوصول إلي محتويات التصنيف الأب أي أنه خاص بالتصنيف الموروث للوصول إليه.