في مقال سابق لنا على منصة أكوا ويب إستعرضنا من خلاله أنواع و فئات البرمجة و كان من بينها البرمجة كائنية التوجه او Object Oriented Programming و أشرنا الى انها واحدة من أهم التقنيات البرمجية التي تسمح لك بإنشاء و تجسيد المشاريع بشكل إحترافي و مهيكل. حتى أننا وفرنا سلسلة مقالات لا بأس بها تتحدث عن تقنيات البرمجة كائنية التوجه مثل الـ Classes ، الـ Objects، الـ Encapsulation ، الـ Constructors و الـ Access Modifiers و غيرها. و هذا المقال سيندرج كذلك ضمن هذه السلسلة لكن هذه المرة سنقوم بشرح 4 مبادئ دفعة واحدة بشكل مبسط و سريع و أيضا مفهوم على ستايل أكوا ويب.
تتكون البرمجة كائنية التوجه او OOP من الكثير من الأساسيات و المفاهيم، لكن عماد هذا النمط من البرمجة يعتمد على 4 أساسيات في الـ OOP وَجَب على كل مبرمج ان يتقن و يحترف هذه المبادئ الأربعة، و هي : Inheritance, Abstraction, Encapsulation و الـ Polymorphisme، سبق و قدمنا مقالا حول الـ Encpasulation لكن سنعيد ذكر هذا المفهوم و شرحه أكثر، فدعونا نبدأ.
أساسيات الـ OOP : الـ Inheritance :
الـ Inheritance او الوراثة من المبادئ الأساسية في الـ OOP و التي تشكله بشكل كبير، هذا المبدأ يأتي ليحل لنا مشكلة تكرار الكود البرمجي من خلال الكلاسات الكثيرة و أيضا هيكلة افضل للكود البرمجي حين نتحدث عن صناعته بشكل عملي و ليس للتدرب.
لنفهم الـ Inheritance بشكل أفضل، عليك ان تكون لديك معرفة قبلية بكل من الكلاس و الـ Object، إنطلق للرابطين الخاصين بهما و إقرأ عنهما قليلا ثم عد من أجل إستكمال الـ Inheritance.
لنفترض ان كل الكائنات الحية لها أرجل و أذرع و قلب مثلا ( لنفترض فقط نعلم ان بعض الكائنات تفتقر الى بعض هذه المكونات ) ثم تنقسم بعدها هذه الكائنات الى أنواع مثلا الإنسان و الحيوان، و نجد ان الإنسان يأتي بخصائص جديدة على خصائص كل الكائنات الحية مثلا العقل، و نجد ان الحيوان يأتي بخاصية جديدة أيضا مثلا " الذيل ".
أساسيات الـ OOP : الـ Encapsulation :
حين تتعامل مع مشروع كبير او ضخم نسبيا، فستحتاج الى تهيئة مجموعة من الـ Attributes و الـ Actions او Functions وسط الكلاس من أجل العمل بها داخل الكلاس، لكن حين الإنتقال من هذا الكلاس إلى كلاس آخر عن طريق الوراثة مثلا فبعض الـ Attributes و الـ Functions الموجودة في الكلاس الأولى قد لا تريد منها الظهور في الكلاس الثانية لكونها ليست ضرورية تارة، او ان تغيير احد قيمها قد يؤدي الى فشل الكود بأكمله، لذلك نقوم بعملية التغليف او الـ Encapsulation الذي يساعدنا على تحديد بالضبط ما إن كنا نرغب في إظهاره خارج الكلاس او في كلاسات محددة فقط و ما الى ذلك.
لنشرح لك الأمر عن قرب، لنتخيل انه وسط الكلاس الخاص بالـ Human أستقبل تاريخ إزدياد المستخدم على شكل Attribute من نوع Date لكن الخارج (Returns) اريده ان يكون العمر (Age) الخاص بالـ Human و ليس تاريخ الإزدياد، إذن سيتوجب علي القيام ببعض العمليات الحسابية وسط الكلاس بنفسه و لكن خارج الكلاس لا أريد إظهار العمليات الحسابية التي قمت بها بل فقط إظهار العمر الخاص بالمستخدم، و هنا سيتوجب علي إستخدام الـ Encapsulation.
يعتمد الـ Encapsulation على 3 مبادئ تقوم بتحديدها قبل الـ Function او الـ Attribute وسط الكلاس، المبدأ الأول و هو Public بحيث تقوم بإنشاء Function بالشكل التالي : Public function getAge. الـ Public تسمح لكل الكلاسات و الـ Objects Instances التي تم إنشائها تبع الكلاس ان بالوصول لهذه الـ Function بدون إستثناء، و ينصح بإستخدامها فقط في حالة أردت تمكين الوصول لدالة او Attributes بشكل عادي.
ثم خاصية Protected التي تسمح لك بتداول الـ Attributes و الـ Functions فقط وسط الكلاس الأب و الكلاسات التي تقوم بالتوريث منه، بحيث ان اي كلاس لا يرث من الكلاس الأب لن يمكنه الحصول على صلاحيات الوصول الى تلك الـ Function.
ثم الخاصية الأخيرة Private و هي تسمح لك بتداول الـ Functions و الـ Attributes فقط وسط الكلاس و لن يظهر إطلاقا لا وسط الكلاس الأبناء او الـ Object Instance، و نستخدمها كثيرا في تهيئة Attributes وسط الكلاس على هيئة Private و تمكين الوصول فقط عبر الـ Access Modifiers.
للمزيد من الشرح و الأمثلة حول الـ Encapsulation راجع مقالنا الآتي .
أساسيات الـ OOP : الـ Abstraction :
الـ Abstraction قد يكون سهل الإستيعاب مبدئيا حين يتم إقرانه بأمثلة بسيطة، و قد تزداد صعوبة إستيعابه قليلا حين نصل لمراحل متقدمة من الـ Abstraction خصوصا حين ننتقل للتعامل مع الـ Abstraction على مستوى الـ Interface مثلا. لكن دعونا نبدأ الشرح رويدا رويدا.
عودة بنا الى مثال الكلاس الخاص بالـ Creatures الأساسي و الأب لكل من كلاس Animal و Human، سنجد انه و بالرغم من إنشاء الكلاسين الإبن لازال بإمكاننا صناعة Object من الكلاس الأم Creatures و هو أمر مربك بحيث علي ان أمنع ذلك و إتاحة فقط صناعة Object عن طريق كلاس Animal او Human لأن أي كائن حي إما سيكون حيواناً او إنساناً في هذه الحالة و لا يمكننا فقط صناعة Creature او كائن حي خارج هذين التصنيفين.
من أجل منع صناعة Object من الكلاس سنستخدم عبارة " Abstract " من أجل تجريد هذه الكلاس فتصير : class abstract creatures، و سيتم إستخدام هذه الكلاس فقط من أجل وصف خصائص كل الكائنات و سيتم إستخدامها فقط من أجل الوراثة لا أقل و لا أكثر.
لكن الـ Abstraction أكبر من ذلك حين نتعامل بها وسط المشاريع الكبرى، فمثلا يمكننا صناعة دالة (Funtion / Method) مجردة أي Abstract، لكن في هذه الحالة يجب على الكلاس بنفسها أيضا ان تكون Abstract و على كل الدوال الأخرى وسط هذه الكلاس ان تكون Abstract كذلك، اما المتغيرات وسط هذا الكلاس يجب ان تكون static final أيضا، حين نقوم بتنفيذ كل هذه القواعد في كلاس واحدة فإن تسميتها لا تصير كلاس و إنما Interface، و هذه أهم الفروقات بين الكلاس و الـ Interface إلى جانب ان الكلاس لا تستطيع الوراثة إلا من كلاس واحد فقط، بينما تستطيع الوراثة من أزيد من Interface عن طريق عبارة Implement لتصير : class human implement creatures .
أساسيات الـ OOP : الـ Polymorphisme :
الـ Polymorphisme ( و يمكننا ترجمته بالعربية الى تعدد الأشكال ) قد يكون من الصعب شرحه بأمثلة بسيطة او بدائية دون الحاجة الى تحديد عمله بالضبط وسط المشروع البرمجي، لكن لدينا بعض الطرق الجيدة من أجلك لنشرح لك الـ Polymorphisme بسهولة بالغة.
أول مرجع لي - شخصيا - في الـ Polymorphisme كان مثالا جميلا جدا و جد بسيط لأحد الأستاذة الموقرين الذين قامو بتدريسي البرمجة في مراحل سابقة و كان المثال على الشكل التالي :
لدينا في البرمجة في لغة الجافا مثلا علامة " + " الجمع، إذا قمنا مثلا بكتابة الكود التالي : System.out.print(5+4) فإن النتيجة المحصل عليها هي 9 بحيث ان علامة " + " قامت بوظيفتها الإعتيادية و هي جمع عددين، لكن في الكود التالي : System.out.print("Aqua" + "Web") فإن النتيجة ستكون : AquaWeb و في هذه الحالة علامة الجمع لم تقم بوظيفتها كعلامة جمع بل قامت بعمل Concatenation للكلمتين.
فنقول ان علامة " + " تقوم بوظيفتين هنا حسب السياق دون تغييرها بنفسها، فإذا كان الطرف على يمين العلامة و يسار العلامة أرقام تقوم بجمعها و إن كان غير ذلك تقوم بربطها.
هذا نفسه مبدأ الـ Polymorphisme لكن بشكل أعمق قليلا، إذ نقوم بصناعة Method في كلاس أساسي، لكن إستخدامها يتغير حسب السياق.
إليك مثال أفضل للـ Polymorphisme أيضا، في كلاس Animal سنضيف مثلا Method إسمها Walk() و تعني ان الحيوان الذي سيتم صناعة Object منه سيقوم بالمشي، لكن ماذا لو كان الحيوان الذي سنقوم بتهيئته هو عبارة عن سمكة مثلا ؟ في هذه الحالة لا يمكننا إستخدام Walk بل Swim تقنيا مع ان كليهما يشرحان و يؤديان نفس المهمة، فلا داعي لأقوم بصناعة أزيد من Method لديها نفس المهمة يمكنني صناعة Method واحدة مثلا Move() و أقوم بإستخدامها حسب المطلوب لكل حيوان، دعنا نشرح لك ذلك عن قرب من خلال هذا المثال :