:: كل المقالات ::

Tue, 13 Dec 2016

البرمجة الكائنية في بيرل ( الجزء الاول ) " المقدمة النظرية "

بسم الله الرحمن الرحيم
سأحاول ان استعرض اساسيات البرمجة الكائنية في بيرل و ذلك في ثلاث مقالات و سنبدأ اليوم بمقدمة تاريخية و نظرية . اولا تجدر الاشارة الى ان بيرل مختلفة عن اغلب لغات البرمجة فالنموذج الكائني في اغلب لغات البرمجة نموذج واحد موحد و مبني في نفس لغة البرمجة . بيرل في الجهة المقابلة لم تكن تدعم البرمجة الكائنية في الاصدارات الاولى و لكن تم اضافة دعم البرمجة الشيئية في الاصدار الخامس العام 1994 . و قد كان هذا النموذج نموذجا مبسطا - خاصة اذا حاكمناه بمعايير هذه الايام - و لا يقدم الا الاساسيات من دعم البرمجة الكائنية و كان على كل مبرمج ان يبني احتياجاته بما يراه و بما تتطلبه بيئة العمل و هذا و ان كان يؤدي الغرض الا انه يترك الباب مفتوحا لكثير من التكرار و الاختلافات . استمر الوضع على هذا الحال الى ان جاء شخص باسم " ستيفن ليتل " في منتصف العقد الماضي و قد كان يعمل على بيرل 6 في مشروع Pugs الذي كان بقيادة المبرمجة العبقرية اودري تانج . هذا الرجل بعد توقف مشروع Pugs عاد الى بيرل 5 و لكنه لم يستطع ان يتعايش مع النموذج الكائني القديم بعد ان رأى قدرات النموذج الكائني في بيرل 6 فقرر ان ينقل النموذج الكائني الذي تقدمه بيرل 6 الى بيرل 5 و بعد محاولات فاشلة نجح المشروع و منه قدم لنا مكتبة Moose التي تقدم نموذجا من اقوى نماذج البرمجة الكائنية الحالية و صار بإمكان مبرمجي بيرل 5 ان يبرمجوا باستخدام احدث انماط البرمجة الكائنية . تعتبر Moose من اهم الاسس التي تقوم عليها البرمجة الحديثة في بيرل و لكن كان عيبها الاساسي هو زمن التشغيل الاولي ما جعلها غير مناسبة لانواع معينة من المشاريع البرمجية مثلا السكربتات البسيطة او البرامج التي تحتاج الى وقت بدء تشغيل سريع جدا مثل بعض تطبيقات الويب. من هنا حاول بعض المبرمجين انشاء بدائل اكثر خفة تناسب هكذا انواع من المشاريع البرمجية فظهرت مكتبات جديدة الى الوجود منها Mouse و Moo. و " مو " هذه برمجها " مات تروت " و قد لاقت اقبالا جيدا ذلك انها تقدم اهم ميزات Moose و تقدم امكانية الترقية الى Moose اذا تطلب الامر ذلك ، كل هذا بالاضافة الى سرعة في بدء التشغيل .
سأقوم بتقسيم الكلام الى عدة اقسام و سنتكلم لاحقا بتفصيل اكثر عن البرمجة الكائنية القديمة في بيرل و من ثم ننتقل للكلام عن مكتبة Moo لانها اسهل للفهم خاصة لمن هم يعرفون البرمجة الكائنية بلغات اخرى مثل جافا . اذا اتممنا الكلام عن Moo سنختم بالكلام عن بعض النماذج البديلة الاخرى من مثل Object::Tiny. ختاما لنستعرض بعض المصطلحات و المفاهيم الاساسية في البرمجة الكائنية - اقتباسا من كتابي ( مختصر دليل لغات البرمجة ) - :
الان ما هي البرمجة الشيئية ؟
هي بكل بساطة عملية محاكاة الواقع في البرمجة فهي النظر الى الوجود على انه مجرد اشياء او كائنات Objects و من ثم محاكاته في عالم البرمجة . كل شيء في هذا الوجود يمكن ان ينظر اليه على انه كائن و كل كائن له خصائص (سمات) Attributes و( افعال) Methods. انواع الخصائص Field type ثابتة كأن تكون قيمة رقمية او نصية و لكن قيم الخصائص Field Value يمكن ان تختلف من حالة الى اخرى . الكلاس Class هو عبارة عن قالب ننشئ منه الكائنات حيث داخل كل كلاس سيتم تعريف خصائص و افعال كل كائن من هذا الكلاس على انه يجب الانتباه الى انه عادة لا يعتبر الكلاس كائنا في حد ذاته الا في اللغات الكائنية الصرفة . اذا عرفنا الان ان الكلاس هو مجرد قالب جاهز لصنع كائنات من نوع ما .
نأتي الان لنشير الى وجود نوع اخر من الكلاسات و هو ما يسمي بالكلاسات المجردة Abstract Class هذه الكلاسات مهمتها تنظيمية فقط و لا يمكن انشاء اي كائن منها مباشرة بل يجب ان يكون هناك كلاس يرث الكلاس المجرد و ان لا يكون هو بدوره كلاسا مجردا حينها فقط يمكن ان ننشئ كائنات تحتوي على خصائص الكلاس المجرد . هنا ذكرنا مصطلح الوراثة Inheritance و هو بكل بساطة عملية انتقال كل خصائص و افعال الكلاس الاب الى الكلاس الابن . لنأخذ بعض الامثلة قبل ان نواصل...
لنتخيل ان هناك مصنعا للسيارات و نريد ان نحاكيه بالرؤية الشيئية يمكن ان نبسط الى شيء مشابه الى :
abstract class Vehicle
abstract class Sedan
class Camry
نلاحظ اننا انشأنا سلسلة من الكلاسات لتنظيم الامور حيث انه بدأنا بكلاس مجرد باسم Vehicle ( مركبة ) و فيه سنعرف الخصائص و الافعال الاساسية التي يجب ان تحتويها كل مركبة ثم انشأنا كلاسا مجردا باسم Sedan يرث كل ما في كلاس Vehicle و يضيف عليها خصائص و افعال كل عربة من نوع سيدان (صالون) اخيرا انشأنا كلاس باسم كامري يرث كل خصائص سيدان و يضيف عليها مميزات و هوية الكامري التي نعرفها .
هنا يطرح السؤال لماذا نجعل من سيدان و Vehicle كلاسات مجردة ؟ لماذا لا نتركها كلاسات طبيعية اليس الغرض هو الوراثة فقط ؟ فيكون الجواب بكل بساطة لاننا نعلم مسبقا اننا لن ننشئ اي كائن من هذه الكلاسات و هذه عادة برمجية جيدة يجب الانتباه لها و على المستوى العملي يتخذ القرار فيها وقت التخطيط Design. نلاحظ ان المخطط الان قابل جدا للتطويع و التعديل في وقت لاحق مثلا باضافة مزيد من انواع السيارات بل و فئات السيارات . في المثال اعلاه كان المخطط ينحو منحى عاموديا بطبيعته اي سلسلة من الاعلى الى الاسفل و لكن مع محاكاة امثلة اكثر تعقيدا سيبدو شكل المخطط و كأنه شجرة ذات غصون متفرعة تصلح لان تحاكي الظواهر الطبيعية قبل الحقائق البرمجية كمشجرة الكائنات الحقيقية من ثدييات ..الخ .
من خلال هذا الاستعراض البسيط بدأنا نعرف سر قوة البرمجة الشيئية في السيطرة على المشاريع العملاقة جدا ، هذه القوة التي تنبع في حقيقة الامر من التجريد .
في البرمجة الاجرائية عادة هناك مشكلة في كون البيانات مشاعة لكل اجزاء البرنامج و لكن في البرمجة الشيئية هناك نوع من الكبسلة (التغليف) Encapsulation اي ان البيانات الخاصة بأي كائن لا يمكن تعديلها الا من خلال ارسال الرسائل Messages الى الكائن و هو بدوره يقوم بعمل اللازم سواء بالتعديل المباشر او اعادة ارسال رسالة اخرى الى كائن اخر طلبا للمساعدة في اتمام الطلب . من هنا نعرف انه في البرمجة الشيئية تتم المهام عن طريق الرسائل و مجموع الرسائل التي يفهمها الكائن تسمى بروتوكولا Protocol بعبارة اخرى البروتوكول او الرسائل التي يمكن للكائن ان يتجاوب معها هي ذاتها الميثودز (الافعال) المعرفة سلفا في كلاس الكائن . نعود هنا للاشارة الى اهمية التجريد هنا ايضا فانا كمستخدم لو اردت ان ارسل ازهارا الى صديقي ما علي سوى ان اذهب الى محل الازهار و اخبره بأنني اريد هذا النوع من الازهار لكي يتم ارساله الى صديقي . هنا نلاحظ انني اعطيت البائع رسالة تمثل طلبا و لا حاجة لي بمعرفة كيفية تعامل البائع لاتمام عملية الارسال. هذه العملية تعرف بالصندقة السوداء Black Boxing اي ان كل كائن مسؤول عن التعامل مع كل رسالة او طلب بطريقته الخاصة التي لا يجب ان يعرف عنها بقية الكائنات اي تفاصيل اضافية .
فبائع الزهور ربما يرسل طلب نقل الزهور الى محطة البريد او الى شركة خاصة او ربما يعطيها لصديق سيذهب الى منطقة صديقي ! و بما اننا نتكلم عن الرسائل لنتكلم عن التعددية Polymorphism و هي من اهم مميزات البرمجة الشيئية و نلخص بأنها قدرة استجابة انواع مختلفة من الكائنات الى رسالة واحدة و لكن كل كائن يفسرها بطريقته الخاصة . المثال المشهور الذي سيوضح لنا هذا المفهوم هو لو ان احد مدراء الشركات عقد اجتماعا و بعد انتهاء الاجتماع قال لموظفيه تابعوا اعمالكم فالرسالة هنا واحدة و لكن كل موظف سيستجيب بطريقته الخاصة فموظف التسويق سيعود الى محل البيع و موظف الدعم الفني سيعود الى مكتب الدعم الفني و هلم جرا.
الان بما اننا نفهم جيدا ميزة التعددية لنعد الى الافعال Methods حيث يمكن ان تعايش حالات اقوى من التعددية بدلا من مجرد التشارك في اسماء الرسائل كما في المثال السابق . الحالة الاكثر انتشارا هي ما يعرف بالاوفرلود Method Overload و هي قدرة الكائن على الاستجابة لرسالة معينة بعدة اشكال مختلفة على حسب نوع و عدد "الخيارات" Parameters المرفقة مع الرسالة مثلا :
jump();
jump(Int myNumber);
فهنا لو اعطانا المرسل عدد مرات القفز في الرسالة لاستجاب الكائن بتكرار عملية القفز عدد المرات المطلوبة و لكن لو ترك المرسل رسالة فارغة من اي رقم ستكون الاستجابة للميثود الافتراضي و لنقل انه يقوم بقفزة واحدة فقط. هذا مثال بسيط و لكنه يوضح فكرة جيدة اخرى و هي توفير انواع مختلفة من الميثود لمعالجة حالات مختلفة من الرسائل و الطلبات .
الحالة الاخرى للتعددية هي ما يعرف بالميثود اوفررايد Method Override و هي شكل من اشكال التعددية يحدث في حال لو كان هناك ميثود في الكلاس الاب و يرثه الكلاس الابن و لكننا نريد للكلاس الابن ان يستجيب بطريقة مغايرة لما يفعله الكلاس الاب . هنا نستخدم الاوفررايد حيث نقوم بإضافة ميثود في كلاس الابن يحمل نفس اسم و توقيع signature الميثود في كلاس الاب و لكن في "جسم" الميثود Method body نقوم باضافة اكواد مغايرة لما هو موجود في كلاس الاب. مثال بسيط :
public class DaddyClass{
public void aMethod(){
//do something here
}}
public class myClass extends DaddyClass {
public void aMethod(){
//respond differently from my daddy
}}
تعدد التوارث Multiple Inheritance
في لغات البرمجة مثل C++ و بيرل هناك امكانية لاي كلاس بأن يرث من اكثر من كلاس، هذا الشيء لا يخلو من الفائدة الكثيرة على الرغم من بعض العيوب و لكن في جافا مثلا لا يمكن للكلاس ان يرث الا من كلاس واحد و هنا يظهر انه سنلاقي صعوبة و محدودية و لكن جافا توفر ما يسمى بالواجهات Interface حيث يمكن لاي كلاس ان يطبق اكثر من واجهة بالاضافة الى وراثته من كلاس معين . عندما يعلن كلاس بأنه يطبق واجهة ما فإننا ننشئ في الحقيقة عقد يجب من خلاله على الكلاس المطبق ان يوفر التطبيق البرمجي لكل ميثود موجود في الواجهة . هذه الخاصية لم تكن متواجدة في النموذج القديم و لكن تم اضافتها في النموذج الحديث للبرمجة الكائنية في بيرل تحت مسمى Roles .
في البرمجة الشيئية كثيرا ما نتكلم عن محددات الترخيص Access Modifier و التي من خلالها نضيف بعدا اخرا من اخفاء المعلومات Data Hiding طبعا لكل لغة برمجية انواع تحكم مختلفة و لكن في جافا مثلا لدينا :
private
protected
default
public
طبعا استخدام هذه الكلمات المفتاحية بالشكل الصحيح يحتاج خبرة و قرار المبرمج نفسه و لكن القاعدة العامة هي كلما كان هناك تشديد في الوصول الى القيم و الميثودز (الافعال) كان افضل فنحن قلنا ان كل كائن يجب ان يكون مسؤولا عن نفسه فلا يفضل التعديل على المعلومات من اماكن كثيرة و مختلفة تؤدي بدورها الى المشاكل و صعوبة كتابة اختبارات للبرنامج .
بعد كل هذا يمكننا الشروع الان في الامثلة التطبيقية ان شاء الله .

دمتم في الرضا ،