فــُـصّـِــلـــَــــت

الفصائل "الفاسقة"

كثيرا ما يتساءل البعض حول الجدوى من تطبيق الكَبْسَلة في نمط البرمجة الكائنية، فيقول لماذا عليَّ أن أنشئ دوالَ أخذٍ وردٍ لكل خاصية عوض أن أجعل الخاصية ظاهرةً بحيث يمكن الوصول إليها مباشرة؟ وجوابا على هذا التساؤل البريء أقدّم هذه التدوينة المجرمة.

مصطلحات التدوينة


  • الكبسلة: هي عملية إخفاء الخصائص لمنع الوصول المباشر إليها.
  • دوال الأخذ والرد: هي الدوال التي يمكن عبرها الوصول إلى الخصائص المخفية.
  • فصيلة: وحدة تحوي خصائص ودوال، يمكن إنشاء كائنات متعددة من نفس الفصيلة.

الفصائل الفاسقة


الفصائل الفاسقة هي التي لا تستخدم الكبسلة، وهي فاسقة لأنها:

  • تسمح لك بالوصول إلى خصوصيتها دون صعوبة.
  • لا تهتم لما أنت تنوي فعله.
  • قد تبدو كاستجابة سريعة لرغباتك.
  • يمكن استعمالها بطرق عديدة، بمعطيات مختلفة، لكن لا واحدة منها مضمونة.
  • لا يمكن الوثوق بها.
  • يجب اختبارها جيدا.
  • تُحدِثُ فوضى عارمة على المدى البعيد.

وعليه فاحرص أيها المبرمج على ستر عورة الفصائل التي تصنع لكي لا نقول عنها "فاسقة".

توضيح


لمن لا يعرف كيف يُطَبِّق الكبسلة في نجم، فإنها كما يلي:

فصيلة إنسان

    ظاهر:
        نص اسم   'هذه خاصية غير مكبسلة'

    خفي:
        نص نسب   'هذه خاصية مكبسلة، ويمكن الوصول إليها من خلال دوال الأخذ والرد أدناه'

    ظاهر:
        خذ_نسب(نص ن)
            نسب = ن
        تم

        رد_نسب() يرد نص
            رد نسب
        تم
تم
أكمل القراءة

إستدعاء مكتبات خارجية من داخل نجم

المستوى: مبتدئ

يصعب على أية لغة برمجةٍ أن تعيش إذا لم تدعم النداءات الخارجية، وإمكانية استعمالها لأكواد مكتوبة بغيرها، ذلك لأنه إن لم تفعل، يجب حينها أن تعاد كتابة كلّ الخدمات والإمكانيات المتاحة حتّى الآن، وتوفير مكتبات لكلّ شيء بهذه اللغة، والأكثر من هذا، وجب الحرص على إعادة كتابة أية تقنية جديدة فور ظهورها، ذلك حتى تدعمها هذه اللغة، وإلا فإنّها تعجز وتشيخ وتصير مُتجاوَزة. وعليه فقد تمّ دعم النداءات الخارجية في لغة نجم وذلك حتى تحافظ لنا على شبابها وحيويتها ومواكبتها للتطورات، فنستمتع بها لوقت أطول.

المكتبات الخارجية


المكتبة هي مجموعة من الأكواد الخام الجاهزة للاستعمال، وهي جاهزة لأنه سبق أن تمت ترجمتها، إلا أنّها لا تحتوي على نقطة دخول من أجل تنفيذها، إذن فهي أكواد آلة لكنها غير قابلة للتنفيذ المباشر، وإنّما فقط إستعمالها من طرف برامج أخرى. لكن من أجل استعمالها يجب معرفة صيغة الملف الذي يحتويها، إذ أنّه لكل لغة برمجة صيغة تستهدفها، فإذا كانت المكتبة مكتوبة بلغة سي أو سي++ فصيغتها تكون مختلفة جدا عن مكتبة مكتوبة بالجافا مثلا، ولهذا فإنّه من أجل دعم المكتبات الخارجية، يجب أوّلا تحديد صيغ المكتبات التي سندعمها.

إلى جانب إختلافها من حيث الصيغة، تختلف المكتبات أيضا من حيث النوع، إذ أنّه يوجد نوعان أساسيان للمكتبات: مكتبات ساكنة، ومكتبات حركية.

المكتبات الساكنة ضد المكتبات الحركية


المكتبة الساكنة هي ملفات يتمّ دمجها وقت الترجمة مع البرنامج الذي يستدعيها لتكوّن بذلك ملفا تنفيذيا واحدًا يضم كلّ شيء، فتصير بذلك كما لو أنّه تمّت كتابتها مع البرنامج، أما المكتبات الحركية فهي ملفات يتم تحميلها وقت التنفيذ إلى حيّز مشترك من الذاكرة، فيمكن بذلك الوصول إليها من خلال أيّ برنامج يحتاجها. تُعرَف المكتبات الساكنة في نظام الويندوز بالامتداد (.lib)، وتُعرَف في نظام اللينكس بالامتداد (.a)، فيما تُعرف المكتبات الحركية في نظام الويندوز بالامتداد (.dll)، وتُعرف في نظام اللينكس بالامتداد (.so).

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

فيما يخصّ نجم


يدعم نجم الآن المكتبات الخارجية الساكنة، والمكتوبة بأية لغة برمجة مُترجَمة، مثل سي وسي++ وغيرها، ذلك بخلاف لغات البرمجة المُفسّرة التي تستهدف آلات وهمية، مثل الجافا، لأنها تُنتِج مكتبات تتطلب توفّر آلتها الوهمية لتنفيذها، مما يُصعّب عملية دعمها.

إذا كانت في حوزتك مكتبة ساكنة (ملفات ".a" أو ملفات ".lib") تريد استخدامها من داخل نجم، فعليك بما يلي:
  1. نسخ الملفات داخل مشروعك.
  2. إضمام هذه الملفات داخل ملفك المصدر.
  3. استدعاء الدوال وكأنها جزء من مصدرك.

مثال حي


ولتوضيح الأمور، لنفترض أنّه لديك مكتبة بلغة سي والتي هي مجموعة من الملفات ".a"، وأنت تريد استخدام الملفّين "libio.a" و "libc.a". فإنّك تقوم أوّلا بنسخهما داخل مشروعك مثلا في "مشروعي\مكتبة\سي\"، ثم تقوم بإضمامهما كما يلي:

ربط "مشروعي\مكتبة\سي\libio.a"
ربط "مشروعي\مكتبة\سي\libc.a"
'... أكواد نجم'
لاحظ أنّه لإضمام مصادر مكتوبة بنجم فنحن نستخدم المفرد ضم، لكن لإضمام مكتبات خارجية فنحن نستخدم المفرد ربط.

إذا أردت مثلا إستدعاء الدالة "sum(int x, int y)" فإنّك تكتب ما يلي:

عدد ع1 = 4
عدد ع2 = 5
استدع "sum"، ع1، ع2   'استدعاء الدالة الخارجية: جمع العددين ع1 و ع2'
عدد ناتج = {عدد}.       'يُمثل المفرد . قيمة آخر عملية تمّت في نجم، وفي هذا السياق هي ردّ الدالة الخارجية'
هذا بشرط أن تكون الدالة sum موجودة فعلا في أحد الملفّين اللذين ثم ربطهما. وفي حال أعطيتَ الدالة الخارجية معطيات أقل مما تتطلّب، فإنّ نجم يعطيها قيمة إفتراضية 0، أما إذا أعطيتها أكثر مما تتطلب، فإن نجم يتجاهل المعطيات الزائدة ببساطة.

تَسهُل ملاحظة الفرق بين دوال نجم، والدوال الخارجية، حيث أنّه لمناداة دالة نجم فنحن نستخدم الصيغة الإعتيادية: اسم_دالة(معطى1، معطى2)، أما لاستدعاء دالة خارجية فنحن نستخدم المفرد استدع.

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

نجم العنكبوتية: رؤيةٌ نحو إدخال نجم للويب

بما أنّ العالم يتجّه الآن لكل ما هو شبكي، بحيث صار النّاس يرفضون تثبيت البرامج على حواسيبهم، وصاروا يفضّلون الاشتغال على الشابِكة، فقد راودتني فكرة الترجمة العنكبوتية، وما أدراك ما الترجمة العنكبوتية؟ هي ببساطة جعل المترجم يعمل عن بعد، بحيث أنّه يمكن كتابة البرامج وترجمتها عبر الشبكة، فإذا فعلنا ذلك، فإننا نستطيع حينها دفع الأمور إلى مستوى أكبر وبناء خادم تطبيقات عبر الشابِكة، وبعبارات أوضح: إمكانية بناء مواقع بلغة نجم. فكيف ذلك؟

مصطلحات التدوينة


  • الشابِكة: كلمة عربية مرادفة لما هو معروف ب "الأنترنت".

الترجمة العنكبوتية


قد راودتني هذه الفكرة وأحببت أن أكتب عنها في مدونتي هذه، ذلك لأن الكتابة تساعدني على تنظيم أفكاري وتوضيحها لنفسي أوّلا ثم لكم أيّها السادة، وهذه الفكرة هي جعل مترجم نجم يعمل عبر الشابكة، إذ أنّك تُرسل إليه الأكواد المصدرية، فيقوم هو من جهته بترجمتها ثم يرسل إليك النتيجة، وهذا سيحتاج إلى برنامج خادم يتنصّت على منفذ معيّن، فيستقبل الرسائل ثم يحلّلها ليستخرج منها الأكواد، فيقوم بعد ذلك بتشغيل مترجم نجم كإجراء فرعي وإعطائه الأكواد المنشود ترجمتها، بعد أن ينتهي إجراء الترجمة من العمل، يقوم البرنامج الخادم بتشغيل الملف التنفيذي الناتج كإجراء فرعي وإرسال مخرجاته إلى الزبون. والزبون هو المتصفّح، بمعنى أنّ هذه العملية قد تنجح بالنسبة للبرامج النصّية، أمّا البرامج الرسومية فلا سبيل لإرسالها عبر الشابكة ذلك لأن الزبون (المتصفّح) لا يعرف كيف يعرضها، وهذا الإشكال يحيلنا إلى التفكير في ما يلي: كيف لنا يا تُرى أن نجعل المتصفّح الزبون يعرض البرامج الرسومية؟ الجواب في الفقرة الموالية.

بناء مواقع بنجم


إذا نجحنا في تحقيق الفكرة أعلاه، نكون حينها قادرين على تنفيذ برامج نصّية عبر الشابِكة، أمّا في ما يتعلّق بالبرامج الرسومية، فنحن كلّنا نعرف أن المتصفّحات المتداولة لا تعرف التعامل مع النوافذ والأزرار والمحرّرات التي يتعامل معها نظام التشغيل عادة، إذ أنّ كلّ ما يفهمه محرّكها الداخلي هو ما نكتبه بلغة الهتمل والجافاسكربت، لدى فإذا استطعنا كتابة برنامجٍ خادمٍ يستطيع إرسال أكواد هتمل ردّا على أكواد نجم التي نرسلها، فإنّنا حينها نكون قادرين على إنشاء مواقع تفاعلية حركية على الشابِكة. نسمي البرنامج الذي يتنصّت على المنفذ ويستقبل الأكواد بخادم الشبكة، ونسمّي البرنامج الذي يُخَرِّج أكواد الهتمل بخادم التطبيقات.

هل يفعلها نجم؟


هل يقدر نجم على بناء خادم الشبكة وخادم التطبيقات؟ الجواب نعم، فنجم يدعم البرمجة الشبكية باستخدام الكائن مقبس، والذي هو عبارة عن قناة يتمّ فتحها بين تطبيقين للتواصل، وبفتح هذه القناة بين المتصفّح والخادم فإنّنا نستطيع إرسال واستقبال الرسائل، وهذا هو أساس مشروعنا.

أما فيما يتعلّق بكيفية تخريج أكواد هتمل إنطلاقا من نجم فيجب معرفة ما يلي: ينقسم مترجم نجم إلى وحدتين كبيرتين: وجه أمامي ووجه خلفي، يهتم الوجه الأمامي بالتحليل اللغوي وتحويل الأكواد وإعادة صياغتها..، فيما يهتم الوجه الخلفي بتخريج الأكواد، يمكن تركيب أيّ وجه خلفي مع الوجه الأمامي، بمعنى أنّه يمكننا تطوير وجه خلفي يقوم بتخريج أكواد هتمل عوض أكواد الآلة وتركيبه مع الوجه الأمامي، وبهذا يكون لنا ما نريده، خادم تطبيقات قادر على بناء صفحات ويب مكتوبة بنجم.


أكمل القراءة

مُحاكات مُحِثّ الويندوز -ج2-

المستوى: متقدم

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

محاكات محث الويندوز -ج1-

تذكير


قمنا بتقسيم المشروع إلى أربع دورات، أنجزنا اثنتان في الجزء الأوّل من التدوين، وفي هذا الجزء سنحاول إتمام المشروع بإنجاز الدورتان الباقيتان. نبدأ إذًا من حيث انتهينا.. الدورة الثالثة.

الدورة الثالثة


هدفنا في هذه الدورة جعل ملف الخرج مؤقتا، وذلك لاستخدامه كصَوْنٍ للخرج، إذ تضع فيه البرامج مخرجاتها ليقرأها المحث، ثم نتخلّص منه بعد ذلك، ونعرض محتواه على شاشة المحث.

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

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

ما سنفعله هو أنّنا سنقرأ من الملفّ قيد الكتابة بشكل متواصل طالما لا يزال الإجراء في طور التنفيذ، لكن المشكل هنا هو أنّ القراءة ما دامت متزامنة، فإنّها لن تترك المجال للكتابة، ذلك لأنّ عملية القراءة متواصلة وما إن نفرغ من عملية قراءة حتى ندخل في أخرى، لدى فإنه لتجاوز هذا المشكل فنحن لن نقوم بالقراءة من الملف إلّا بعد أن نتأكد بأنّه تمت كتابة شيء فيه، أنظر الكود:

أمر_آخر(نص اسم، نص معطيات)
    نص اسم_كامل = رد_اسم_كامل(اسم)
    لو ليس نظام_ملفات.هو_موجود(اسم_كامل)
        ملف_خرج.زد_نص("ما أدخلته ليس أمرًا صالحًا للتنفيذ")
    أما لو نظام_ملفات.هو_مجلد(اسم_كامل)
        ملف_خرج.زد_نص("قد أدخلت عنوان مجلد، لا يمكن تنفيذه")
    وإلا
        إج_حالي = إجراء جديد(اسم_كامل، {عدد}عدم، ملف_خرج.رد_مقبض()، ملف_خرج.رد_مقبض())
        إج_حالي.نفذ(معطيات)
        طالما إج_حالي.هو_حي()
            لو ملف_خرج.رد_حجم() > 0
                عرض_ملف()
            تم
        تم
    تم
تم
قبل تنفيذ الأمر فنحن نقوم ببعض الفحوصات للتأكد من أنّ العنوان المطلوب تنفيذه هو عنوان موجود، وبأنّه فعلا ملف لا مجلد، نقوم بعد ذلك بإنشاء الإجراء وإعطائه مقابض الدخل والخرج الأساسية، ثم تنفيذه، وطالما هو قيد التنفيذ، فنحن نقيس حجمه، فإذا صار أكبر من صفر، فحينها نعلم أنه قد تمت كتابة شيء في الملف، نقوم عندئذ بالقراءة لكن على الشكل التالي:

عرض_ملف()
    ملف_خرج.زحف(ملف.من_أوله، 0)
    نص ن = ملف_خرج.إقرأ_الكل()
    ملف_خرج.بتر(0)
    جدول<نص> جص = ن.شق(حرف.رس)
    لأجل عدد ع=0، ع<جص.طول، ع++
        لو ع = 0
            سطور.خذ(سطور.طول-1، سطر_حالي() + جص.صف(ع))
        وإلا
            سطر_جديد(جص.صف(ع))
        تم
        ن_محث.حدّث()
    تم
تم
بدأنا بالزحف إلى بداية الملف، ذلك لأنه بعد الكتابة فإن مؤشر الملف يكون عند نهايته، فإذا قرأنا من النهاية فنحن لن نجد ما نقرأه وستعود دالة القراءة دون نتيجة، نقرأ بعد ذلك كلّ محتوى الملف، ثم نقوم بتصفير حجمه، أي أننا نقوم بمحو محتواه وإرجاع حجمه إلى صفر، وهذا أمر مهم لأنه إن لم نفعل فنحن دائما سنجد حجم الملف أكبر من صفر وسنكرر قراءة ما تمّت قراءته سابقا. نقسّم بعد ذلك النصّ الذي قرأناه حسب السطور ليسهل تخزينه في صون الخرج وعرضه على الشاشة.

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

نُكمِلُ قريبًا مع الدورة الرابعة.

أكمل القراءة

مُحاكات مُحِثّ الويندوز -ج1-

المستوى: متقدم

نظرا لعدم توفّر مُحثٍ (سطر أوامر) يدعم الحروف العربية بفعالية، فقد أدركتني الحاجة إلى تصميم محث عربي من عدم، وعليه قمت بتصميم وإنجاز برنامج يحاكي المحث القياسي الموجود في الويندوز، يدعم افتراضيا المحارف العربية، ويدعم نسخًا عربية لعدد من الأوامر المتداولة.

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

ما هو المُحِث؟


المُحِث ويدعى أيضا الطرفية أو سطر الأوامر، هو واجهة للتواصل بين المستخدم ونظام التشغيل، إذ يعطي المستخدم أوامرًا للنظام عبر المحث ليقوم هذا الأخير بعرض النتائج، وقد سمّي بالمحث لأنه يحث المستخدم على إدخال أوامر للنظام، تسمّى البرامج التي تعمل على المحث برامج نصّية، ذلك لأنها تتفاعل مع المستخدم عن طريق النصوص، والمحث هو تقليد للواجهات النّصّية القديمة التي كانت سائدة قبل ظهور الواجهات الرسومية.

الحاجة إلى مُحِث


لقد حاولتُ مرارًا إعداد محث الويندوز لكي يدعم النصوص العربية بكفاءة، وقد نجحت في ذلك لكن إلى حد غير مُرضي، ذلك لأن مُحِثّ الويندوز لم يُصمّم ليدعم الحروف الغير الإنجليزية، ولقد بحتث مطوّلا على الأنترنت ووجدت محاكيات، بعضها أفضل من بعض في التعامل مع العربية، إلّا أنّها تبقى كلّها قاصرة خصوصا عند تمرير المعطيات إلى البرامج، والتعرف على النصوص المُدخلة.

لهذا فقد قرّرت إنشاء محاكي محثٍ يدعم العربية، ذلك لأنّني أحتاج التعامل مع النصوص العربية بكثرة من خلال البرامج التي أشغّلها، تمّ تطوير المحاكي بلغة البرمجة نجم، وهو يشتغل على نظام الويندوز ويعمل تماما مثل محث الويندوز، إذ تُدخل سطر الأمر (اسم برنامج ومعطياته) فينفّذه ويعرض لك ردّه.

قاموس مصطلحات هذا التدوين


  • صَوْن: حيّز ذاكرة مؤقت يستخدم غالبا لنقل البيانات من مكان إلى مكان، أو لتخزين البيانات بشكل مؤقت.
  • طابور: مجموعة من العناصر مرتبة واحدا تلو الآخر.
  • مِحرَف: حرف عربي أو عجمي، أو رقم، أو علامة ترقيم، أو مسافة أو فراغ أو عودة إلى السطر...
  • إجراء: برنامج قيد التنفيذ.
  • خيط: سلسلة تعليمات يتم تنفيذها، يتكون الإجراء من خيط واحد أو أكثر، ويمكن تنفيذ عدّة خيوط بالتزامن.
  • مقبض: هو رقم يستخدمه نظام التشغيل لتعريف كائن معيّن كملف أو إجراء أو خيط..
  • حجب دالة: إعادة كتابة دالة موجودة في الفصيلة الموروثة.

خلفيات نظرية


ما سنقوم به أساسا هو إنشاء برنامج رسومي يعمل كالمحث، يتكوّن من نافذة فقط، ومن خلال الأكواد سنجعل النافذة تعمل تماما كالمحث، التحدي يكمن في تشغيل الأوامر (البرامج) وعرض ردودها في وقت حقيقي. سنبدأ أوّلا بالتعرّف على كيفية عمل المحث والفكرة المحورية التي سنعتمدها لبلوغ هدفنا.

يتكون المحث أساسا من صونٍ للدخْل وصونٍ واحد أو أكثر للخرْج. يحوي صون الدخل طابورًا من تسجيلات الدخل، كلٌ منها يضم معلومات حول حدث دخْل معيّن، منها أحداث لوحة المفاتيح كالضغط على مفتاح وتركه، وأحداث الفأرة كتحريكها والضغط على زرٍ وتركه. أمّا صونُ الخرج ويسمى أيضا صون الشاشة، هو عبارة عن جدول ذو بُعدين من المحارفِ وألوانِها ليتم عرضها على شاشة المحث. يمكن لأي عدد من الإجراءات مشاركة محث واحد.

سنقوم بإنشاء نافذة، سنحاول جعل هذه النافذة هي الدّخل والخرج الأساسي للبرنامج، وذلك عبر إنشاء ملفّين مؤقتين على الذاكرة وجعل مقبضَيهما مقبضَي الدخل والخرج الأساسيَين، وعند تنفيذ أمر معيّن، يقوم البرنامج بإنشاء إجراء جديد وتوريثه مقابض الدّخل والخرج الأساسية، وهكذا سيقوم هذا الإجراء الفرعي بكتابة مُخرَجاته على ملف الخرج المؤقت.. يقوم برنامجنا بقراءة محتوى الملف المؤقت وعرضه على النافذة.

خطة العمل


سنقسّم المشروع إلى دورات برمجية قصيرة وسريعة، ذلك حتّى نتمكّن من مواجهة المشاكل واحدا تلو الآخر لا كلّها مجتمعة، وللتذكير تسمى هذه الطريقة بالتطوير بالدورات، وهي تعتمد نظرية فرّق تسد أو إقسِم واهزم.

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

الدورة الثانية: بالضغط على إدخال، يتم تنفيذ الأوامر التي تمت كتابتها على النافذة وتوجيه مخرجاتها إلى ملف على القرص الصلب والتأكد من سلامة ترميزها.

الدورة الثالثة: جعل الملف مؤقتا وقراءة محتواه وعرضه على الشاشة في كل مرة يتم تنفيذ أمر معين، مما يعطي إنطباع الوقت الحقيقي.

الدورة الرابعة: دعم الدّخل بحيث تستطيع البرامج التفاعل مع ما يكتبه المستخدم، وذلك عن طريق الملف المؤقت الثاني الخاص بالدّخل، وسوف يعمل بنفس طريقة ملفّ الخرج الذي سبق أن صنعناه في الدورات السابقة.

الدورة الأولى


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

نبدأ بإنشاء الفصيلة الأساسية التي تضم عناصر المشروع، نسمّيها نافذة_محث:

فصيلة نافذة_محث يرث مراقب_أحداث

    خفي:
        نافذة ن_محث            'النافذة الرئيسية'
        خط خط_كوفي           'سيتم تحميل الخط من ملف على القرص'
        أحخز خلفية              'لون خلفية النافذة بمعيار أحمر أخضر أزرق'
        أحخز لون_نص          'لون الخط على النافذة'
        رقعة رقع                 'رقعة الرسم'
        جدول<نص> سطور    'صون الشاشة'
        عدد أقصى    'عدد السطور الأقصى التي يمكن عرضها على الشاشة'

    ظاهر:
        جديد()
            ن_محث = نافذة جديد("المحث"، 800، 600، 0، 0)  'إنشاء نافذة عنوانها المحث'<
            ن_محث.خذ_مراقب_أحداث({مراقب_أحداث}هذا)    'جعل هذا الكائن مراقب أحداث النافذة'
            خط_كوفي = خط جديد({متفاعل}ن_محث، "مسار ملف الخط"، "كوفي عربي"، 14)
            عدد ارتفاع_شاشة = 600 - (خط_كوفي.ارتفاع_حرف×2) 'الارتفاع الأقصى لعرض الحروف'
            أقصى = ارتفاع_شاشة ÷ خط_كوفي.ارتفاع_حرف   'عدد السطور الأقصى'
            خلفية = أحخز جديد(0، 0، 0)    'خلفية سوداء'
            لون_نص = أحخز جديد(255، 255، 255)    'نص أبيض'
        تم

        عرض()
            ن_محث.عرض()   'عرض النافذة. تذكير: هذه الدالة لا تعود إلا بعد إغلاق النافذة'
        تم
تم
تقوم الأكواد أعلاه بإنشاء وتمهيد الكائنات التي سنتعامل معها، لاحظ أن الفصيلة نافذة_محث ترث الفصيلة مراقب_أحداث، وهي فصيلة مجرّدة تُعرّف الدوال الأساسية لدعم مختلف الأحداث. قمنا أيضا بتحميل الخط الكوفي من ملف خطوط، يجب تعويض "مسار ملف خط" بعنوان الملف على الحاسوب، وكذلك تعويض النص "كوفي عربي" بإسم الخط في ملف الخطوط، وغالبا ما يكون الإسم بحروف لاتينية.

بعد أن صارت كائناتنا جاهزة، ننتقل الآن إلى دعم الأحداث عن طريق حجب الدوال المناسبة في مراقب_الأحداث، دعنا نبدأ بدعم أحداث لوحة المفاتيح.

'حجب عند_ضغط_مفتاح من مراقب_أحداث'
عند_ضغط_مفتاح(متفاعل من، حرف ح)
    لو ح = حرف.بس         'ضغط على إدخال. بس = بداية سطر'
        لو سطور.طول = أقصى  'وصلنا إلى أسفل الصفحة'
            سطور.حذف(0)    'حذف أوّل سطر، لن يتم عرضه على الشاشة'
        تم
        سطور.زد("محث>")    'إضافة صفّ جديد إلى جدول السطور'
        {نافذة}من.حدّث()        'إعادة رسم النافذة لعرض التغييرات'
    أما لو ح = حرف.مسح    'ضغط على مسح'
        لو سطر_حالي().طول > 4   'لا تمسح الكلمة محث>'
            سطر_حالي().طول--
            {نافذة}من.حدّث()
        تم
    وإلا   'ضغط على حرف'
        سطور,خذ(سطور.طول-1، سطر_حالي()+ح)   'زد الحرف في السطر الأخير'
        {نافذة}من.حدّث()
    تم
تم
'رد آخر سطر في جدول السطور المعروضة على المحث'
سطر_حالي() يرد نص
    رد سطور.صف(سطور.طول-1)
تم
إلى الآن، نحن نترقب أحداث لوحة المفاتيح ونخزّن الحروف المضغوطة في صون الشاشة الذي هو عبارة عن جدول نصوص سمّيناه سطور، كلّ سطر في الجدول يمثّل سطرأ على الشاشة، وكلّ سطر يحوي نصّا، عند الضغط على حرف معيّن، فنحن نضيفه إلى النصّ الموجود في السطر الأخير.

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

تبقى الآن عملية الرسم على الشاشة، وذلك لعرض الحروف التي نخزّنها، وكذلك تلوين الشاشة بالأسود وهو لون المحث الاعتيادي، من أجل ذلك نقوم بحجب الدالة عند_رسم، وهو الحدث الذي يمثّل إعادة رسم الشاشة، وهو يطرأ في كلّ مرّة يتم فيها تحريك الشاشة أو تحجيمها... وكذلك في كلّ مرّة نستدعي الدالة حدّث، وهذا ما كنّا نفعله بعد كلّ عملية إضافة حرف جديد أو مسحه (سطور 5، 9، 13 أعلاه). وللتوضيح، لاحظ المعطى "من"، وهو كائن من فصيلة متفاعل، ذلك لأن كلّ كائن رسومي هو متفاعل (يرث من الفصيلة متفاعل)، يعبّر المعطى "من" عن الكائن الذي وقع عليه الحدث (ضغط_مفتاح في هذه الحالة)، وبما أنّنا نملك كائنًا وحيدًا هو نافذتنا الأساسية، فنحن نعرف أن "من" هو هذه النافذة، لدى فنحن نحوّله إلى نافذة دون أيّ تخوّف ونستدعي دالة التحديث التي تسبب حدث عند_رسم وبالتالي إعادة رسم النافذة لعرض التغييرات.

ننتقل الآن إلى حجب الدالة عند_رسم، وفيها نقوم برسم النصوص على الشاشة، وذلك باستخدام الكائن رقعة، وهو المسؤول عن الرسم والتخطيط والتلوين..

'حجب عند_رسم من مراقب_أحداث'
عند_رسم(نافذة من)
    لو سطور = عدم  'أوّل مرّة يتم فيها الرسم'
        سطور = ["محث>"]   'جعل كلمة محث> في بداية السطر'
    تم
    رقع = ن_محث.رد_رقعة()   'رد رقعة النافذة للرسم عليها'
    رقع.بدء_رسم()   'تمهيد الرقعة للرسم'
    رقع.ملء(خلفية)   'تلوين خلفية الرقعة (النافذة) بالأسود'
    رقع.خذ_خلف_نص(خلفية)   'تلوين خلفية النصوص بالأسود'
    رقع.خذ_لون_نص(لون_نص)    'تلوين النصوص بالأبيض'
    رقع.خذ_خط(خط_كوفي)    'إعتماد الخط الكوفي الذي تمّ تحميله في دالة التكوين'
    'عرض السطور'
    لأجل عدد ع=0، ع<سطور.طول، ع++
        رقع.عرض_نص(سطور.صف(ع)، 0، ع×خط_كوفي.ارتفاع_حرف)
    تم
    رقع.ختم_رسم()    'نهاية الرسم'
تم
يتم استدعاء عند_رسم تلقائيا عند كلّ حدث يغيّر معالم النافذة، ونحن نعيد أخذ رقعة النافذة في كلّ مرّة لكي تتسع رقعة الرسم إذا تمّ تكبير النافذة وتتقلّص بتصغيرها، وهكذا تبقى رقعة الرسم دائما منسوبة إلى إطار النافذة، نقوم بطلاء الرقعة بالأسود لتصير النافذة كلّها سوداء، ثم نكتب محتوى السطور وهو ما نسمّيه صون الشاشة، أو صون الخرج، وهو ما تعرضه النافذة. نبدأ الرسم (الكتابة) دائما من الأفصول 0، ومن الأرتوب الذي يناسب رقم السطر الحالي مضروبا في ارتفاع كلّ حرف في الخط الكوفي، ذلك لكي تتمّ العودة إلى السطر دون تداخل مع السطر الذي فوقه.

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

يمكن تحميل الكود الكامل للدورة الأولى من خلال الرابط الملحق أسفل التدوين، وهذه صورة لما قد صنعت أيدينا حتى الآن:

محث الويندوز العربي في دورته الأولى

الدورة الثانية


سنقوم في هذه الدورة بتنفيذ الأوامر التي تتم كتابتها عوض الرجوع إلى السطر دون تجاوب، سنقوم بإعادة توجيه مخرجات (ردود) هذه البرامج إلى ملف على القرص الصلب، ذلك لكي نستطيع فتح الملف والتأكد من صحّة ترميز النصوص. على أن نقوم في دورة مقبلة بجعل هذا الملف مؤقتًا حتى يظهر على القرص الصلب ويتم حذفه بعد الانتهاء منه.

أشرنا سابقا إلى أنّه في كلّ دورة ننشئ برنامجا مستقلا قابلا للتنفيذ والاختبار، لكن هذا لا يعني أنّنا لا نتسطيع التغيير في الأكواد التي تمّ إنشاؤها في الدورة السابقة، فمن أجل تحقيق متطلبات الدورة الحالية، قد نحتاج إلى تعديل بعض مقاطع الأكواد لتطويعها حسب ما نراه يناسب الدورة.

أوّل ما سنبدأ به هو إضافة كائنٍ "ملف" إلى قائمة كائنات المشروع.

    خفي:
       نافذة ن_محث            'النافذة الرئيسية'
       خط خط_كوفي           'سيتم تحميل الخط من ملف على القرص'
       أحخز خلفية              'لون خلفية النافذة بمعيار أحمر أخضر أزرق'
       أحخز لون_نص          'لون الخط على النافذة'
       رقعة رقع                 'رقعة الرسم'
       جدول<نص> سطور    'صون الشاشة'
       عدد أقصى         'عدد السطور الأقصى التي يمكن عرضها على الشاشة'
       ملف ملف_خرج      'الملف الذي سيضم مخرجات الأوامر'
ثم نباشر بتمهيد الكائن ملف_خرج في دالة التكوين.

    ظاهر:
        جديد()
            ...
            ملف_خرج = ملف جديد(تنفيذ.رد_مسار_تطبيق() + "خرج.نص"، ملف.للكل، ملف.أنشئ_دائما)
        تم
سيتم إنشاء ملفّنا في نفس مجلّد التنفيذ الحالي، وسيكون اسمه "خرج.نص"، يشير المعطى ملف.للكل إلى أنّ الملف سيكون مفتوحًا للقراءة وللكتابة، ويشير المعطى ملف.أنشئ_دائما إلى أنّه سيتم إنشاء ملف جديد حتى ولو كان موجودًا بالفعل، إذ يحذفه وينشئ آخر مكانه.

عند الضغط على إدخال، نريد من برنامجنا أن ينفّذ الأمر المكتوب، لهذا سنقوم بتطويع دالة عند_ضغط_مفتاح كالتالي:

'حجب عند_ضغط_مفتاح من مراقب_أحداث'
عند_ضغط_مفتاح(متفاعل من، حرف ح)
    لو ح = حرف.بس         'ضغط على إدخال. بس = بداية سطر'
        سطر_جديد()   'هنا سيتم تنفيذ الأمر'
        {نافذة}من.حدّث()
    أما لو ...
    ...
تم
تَمّ استدعاء الدالة سطر_جديد في السطر 4 أعلاه، وهي مسؤولة عن تنفيذ الأمر ثم العودة إلى السطر:

سطر_جديد()
    لو سطور.طول = أقصى  'آخر الصفحة'
        سطور.حذف(0)  'حذف أوّل سطر'
    تم
    نفذ_أمر()
    سطور.زد("محث>")
تم
'تحليل سطر الأمر وتنفيذه كإجراء فرعي'  
نفذ_أمر()
    نص سطر_أمر = سطر_حالي().رد_قطعة(4، سطر_حالي().طول-1) 'استثناء محث>'
    جدول<نص> كلمات = سطر_أمر.شق(" ")  'تقسيم الأمر إلى كلمات حسب الفراغات'
    نص اسم_برنامج = كلمات.صف(0)  'أوّل كلمة هي اسم برنامج التنفيذ'
    نص معطيات = ""   'تركيب المعطيات من باقي الكلمات'
    لأجل عدد ع=1، ع<كلمات.طول، ع++
        معطيات = معطيات + كلمات.صف(ع)
    تم
    ملف_خرج.فتح()   'فتح الملف لكتابة المخرجات'
    'إنشاء إجراء جديد، يرث مقبض ملف_خرج كمقبض خرج أساسي'
    إجراء إج_برنامج = إجراء جديد(اسم_برنامج، {عدد}عدم، ملف_خرج.رد_مقبض()، ملف_خرج.رد_مقبض())
    'تنفيذ الإجراء بالمعطيات'
    إج_برنامج.نفذ(معطيات، إجراء.انتظر_نهاية)
    ملف_خرج.غلق()
تم
لقد قمتُ أيضا بدعم بعض الأوامر المضمنة التي هي ليست برامج يقوم المحث بتنفيذها وإنّما هي أوامر يدعمها المحث مباشرة وهي: الأمر "إلى" والأمر "أين"، حيث أن الأمر "أين" يعطيك العنوان الحالي حيث أنت، والأمر "إلى" ينتقل بك إلى عنوان جديد. لن أستعرض هذه الأكواد في هذا التدوين خشية التطويل، تجدونها في مصدر البرنامج الملحق أسفل التدوين.

عند تنفيذ البرنامج الناتج من هذه الدورة، يمكننا تنفيذ أيّ ملفّ قابل للتنفيذ على الحاسوب، وذلك إمّا بكتابة عنوان البرنامج كاملا، أو بالإنتقال إلى مجلّد البرنامج باستخدام الأمر "إلى عنوان_مجلد"، ثم كتابة اسمه والضغط على إدخال. يتمّ بذلك تنفيذ البرنامج وتوجيه مخرجاته إلى الملف "خرج.نص"، إذا فتحنا هذا الملفّ فإنّنا نرى ما ردّه البرنامج بالترميز الصحيح. وبهذا فإنّنا قد أنجزنا متطلّبات الدورة الثانية، فماذا بعد؟ إي نعم، الدورة الثالثة.
أكمل القراءة

البرمجة الكائنية: لماذا وكيف؟

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

حرفة البرمجة


بعد أن كان فرعا من علم الرياضيات، تطور علم الحاسوب ليصبح مستقلا بذاته، ونشَأَت بفضله حرف واختصاصات عديدة، فرضت نفسها في السوق فأصبح هناك إنتاج وحاجة وزبائن.. فهي الآن صناعة ذات قيمة عالية وتحقق مكاسب عظيمة. تُنتج هذه الصناعة بالأساس برامج الحاسوب، وهو منتوج له خصائص كأي منتوج آخر، فهو يباع ويشترى، يعمل ويتعطل، يبلى ويُصان وله دورة حياة، لكن ما يميّزه أننا لا نستطيع لمسه، فهو مُجَرّدٌ ولا ندركه بحواسّنا، نراه، نستعمله، لكنه فقط شبه موجود، فهو ليس حقيقي كالسيارة مثلا، وهذا يطرح المشكل الأساس: كيف نضمن جودة المنتوج؟ أو ما نسميه بالنضج البرمجي. من أجل هذا بدأ علماء الحاسوب والبرمجة يفكرون في وضع معايير ومقاييس لضمان الجودة، ومن هنا نبعت فكرة أبرقت لها العيون: نجعل البرمجيات تحاكي الواقع ونتعامل معها كما لو كانت ملموسة، فيصبح المبرمجون يتعاملون مع كائنات لها خصائص ووظائف، وهكذا تصير هذه الصناعة المجرّدة كسائر الصناعات، لها مالهن وعليها ما عليهن.

من جهة أخرى


بعد تطوّر القدرة الحسابية والتخزينية للحواسيب زاد حجم وتعقيد البرمجيات، فأصبحت المشاريع البرمجية أضخم وأعظم، تستدعي طواقم وورشات عمل وإدارة للمهام وتدابير عدّة، يسعى نمط البرمجة الكائنية إلى ضبط هذه المشاريع والتحكم في سيرورتها وضمان نجاحها من خلال تطبيق النظريات المحورية التالية:

أ. البنيوية: تقسيم المشكل إلى مشاكل فرعية يمكن حلها منفصلة.

 

وثيقة 1: البنيوية

ب. التجريد (تسهيل الفهم): مصطلحات مجال البرنامج معكوسة في الحل البرمجي.

 

وثيقة 2: التجريد

ج. الكبسلة (إخفاء المعلومات): إخفاء التعقيدات البرمجية على المستعمل، وتعامله مع الواجهة فقط.

 

وثيقة 3: الكبسلة

د. التركيب: بناء أنظمة جديدة من خلال تركيب الوحدات. 

 

وثيقة 4: التركيب

ه. السلالة: التطوير التدريجي للوحدات البسيطة والصغيرة إلى وحدات أكبر وأعقد.

 

وثيقة 5: السلالة

و. الاستمرارية: تغيير أو تعديل الوحدات لا يؤثر على النظام.

 

وثيقة 6: الاستمرارية

 

مفاهيم البرمجة الكائنية


أصبحت برمجة الكائنات علما قائما، هناك من يتقنه وهناك من لا يفعل، ومن يتقنه يُسمى مهندس نظم برمجية، يَعنَى المهندس بدراسة كيفية تحديد الكائنات من خلال اصطلاحات المشكل المطروح، وانشاء العلاقات فيما بينها، وبناء كائنات معقدة من خلال أخرى بسيطة، كل هذا لا يتقنه المرء بين ليلة وضحاها، فهي مهارة تُكتَسب بالخبرة والصبر. ومن أجل ذلك نسرد مختلف المفاهيم المؤسسة لهذا العلم.

أ. ما معنى كائن؟


الكائن هو وحدة مستقلة لها خصائص ووظائف تحدد سلوكه وطبيعته وسط مختلف البيئات (الأنظمة). مثلا: في بيئة المصرف هناك كائنات نعتبرها مادية كالزبون والعقد، وأخرى نعتبرها مجردة كالحساب المصرفي.
وفي اصطلاحات البرمجة الكائنية فالكائن هو نسخة من فصيلة.

ب. ما معنى فصيلة؟


الفصيلة هي الصورة الشاملة والتمثيل القياسي الذي يُستنسخ عليه الكائن، فهي تحدد خصائصه وسلوكاته، وبها يتم تكوين عدد لا يحصر من كائنات نفس الفصيلة. تتكون الفصيلة من ثلاثة أشياء: اسم وخصائص ووظائف. مثال:
اسم الفصيلة: زبون.
الخصائص: اسم، نسب، عنوان.
الوظائف: إمضاء عقد، طلب انتساب.
بهذا نستطيع استنساخ كائنات كعمر وعبد الله من فصيلة زبون.

ج. ما معنى كبسَلة؟


تُخَزِن الفصيلة التفاصيل الداخلية للكائن وتمنع الوصول إليها إلا من خلال واجهات، فنستعمل هذه الواجهات للتحكم في الكائن، وهذا يضمن حماية لخصائص هذا الكائن بحيث لا نستطيع تغييرها مباشرة، وكذلك يضمن عدم تأثر النظام بالتغييرات الداخلية التي قد تطرأ على الكائن، هذا ﻷن النظام لا يعرف عنها شيئا ويتعامل مع الواجهة فقط. ولهذا فالفصيلة هي كبسولة تحفظ خصائص الكائن.
يتم الوصول إلى الخصائص المخفية عبر دوال نسميها دوال الأخذ والرد، ذلك لأنه عبرها يتم أخذ القيم الجديدة لهذه الخصائص المخفية وردها.. وهي تكتب عادة: خذ_خاصية()، رد_خاصية().

د. ما معنى علاقة؟


من خلال العلاقات بين الفصائل، يستطيع كائن دفع آخر للقيام بوظيفة لصالحه، فهناك علاقة بين الزبون والحساب المصرفي، بحيث أن الأول يستعين بالتاني لإيداع المال وفحص الرصيد مثلا.. وهذه العلاقة نسميها علاقة عادية، ولها منحى، بمعنى أنه إذا كان منحى العلاقة من الزبون إلى الحساب فهذا يعني أن الزبون وحده من يستعمل الحساب (يعلم بوجوده)، أما إذا كان المنحى من الحساب إلى الزبون فهذا يعني أن الحساب وحده من يستعمل الزبون (ويعلم بوجوده) وهذا تصميم خاطئ في مثالنا، كما يمكن للمنحى أن يكون في الاتجاهين معا. هناك نوعان إضافيان من العلاقات هما علاقة التجميع وعلاقة التركيب، وهذه الأنواع الثلاثة تُربك المتعلم حيث أنها متقاربة من حيث الشكل.

ه. ما الفرق بين العلاقة العادية، وعلاقة التجميع وعلاقة التركيب؟


علاقة التجميع هي نوع خاص من العلاقة العادية، وما يميزها هو أنه إذا كانت علاقة تجميع بين كائنين أ و ب، ومنحاها من أ إلى ب، فهذا يعني أن أ يحتوي ب. مثال على ذلك العلاقة بين الكائنين مصرف ومدير المصرف، فالأول يحتوي على الثاني، أي أن مدير المصرف يكون داخل المصرف.

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

و. ما معنى التجريد والتعميم؟


التجريد والتعميم هما مفهومان متكاملان، ويهدفان إلى تقليص التعقيد وتعدد الكائنات في الأنظمة، فالتجريد يكون بتحديد فصائل مجردة تُعمّم مجالا معيّنا. مثلا: يمكننا اعتبار الفصيلة المجردة بناء بحيث ننشئ من خلالها فصيلة المصرف أو المنزل.. وبهذا نكون قد عمّمنا مفهوم المصرف إلى بناء.

ز. ما معنى واجهة؟


تعنَى الواجهات بتحديد بنية الفصيلة، أو الهيئة الخارجية للفصيلة دون تركيبها الداخلي، فيمكن من خلالها التعامل مع كائنات الفصيلة دون الحاجة إلى التعرف على بنيتها وتعقيدها الباطني، وهذا المفهوم يكون مهما جدا عندما تكون البنية الداخلية للفصيلة في تغيّر مستمر، فبواسطة الواجهات يمكن استعمال الفصيلة دون التأثر بالتغييرات الطارئة عليها. هناك من يقول بأنه يجب تحديد واجهة لكل فصيلة بينما يرى آخرون أن هذا رأي متطرف.

ح. ما معنى وراثة؟


يمكن لفصيلة جديدة أن تُنشَئ من فصيلة موجودة، فترث خاصياتها ووظائفها ويمكنها تمديدها بتعيين خصائص ووظائف تخصّها، نسمي هذا بالوراثة. ونقول أن وظائف الفصيلة الوارثة تَحْجُبُ وظائف الفصيلة الموروثة.

ط. ما معنى تعدد الأوجه؟


يعني تعدد الأوجه أن نفس الوظيفة يمكن أن يقوم بها عدد مختلف من الكائنات وبطرق وأشكال متعددة. فالناقة تسير والسيارة تسير والإنسان يسير، إنها نفس الوظيفة 'السير' إنما هو كلٌ يسير بطريقته الخاصة. في البرمجة الكائنية يطبَّق تعدد الأوجه بأشكال مختلفة أهمها تحميل الدوال وحجب الدوال وهذان المفهومان تقنيان نتكلم عنهما في مقالة أخرى.

خاتمة


كانت هذه إطلالة خفيفة على نمط البرمجة الكائنية، ومن هذا وذاك نرى أن هذا النمط مثالي للمشاريع البرمجية الكبيرة والمتوسطة ويُنصح استعماله في الصغيرة أيضا، وذلك للحفاظ على نمط برمجة قياسي واحد. يستدعي تصميم الكائنات والربط بينها عمليات التحليل والتصميم والنمذجة، وُضِعَت من أجل هذا مناهج وقواعد سنفيض الكلام عنها في موضوع لاحق.

إلى جانب البرمجة الكائنية، هناك أنماط أخرى كالبرمجة البياناتية والبرمجة الخدماتية وغيرها.. لكن استعمالها مازال غير مستقل عن برمجة الكائنات ولهذا يتم حالياً دمج كل هذه الأنماط تحت راية البرمجة الكائنية.



















أكمل القراءة

تحليل وتصميم الكائنات البرمجية (1)

المستوى: مبتدئ

يتكون هذا الموضوع من أجزاء عديدة وهذا الجزء الأول منها.

برمجة الكائنات هو علم يهتم بمحاكات الكائنات الموجودة وبرمجتها على الحاسوب، وبهذا نقوم بتكوين عالم برمجي يختص بنطاق معين كالمكتبة مثلا، فمن أجل تكوين مكتبة برمجية قد نحتاج لتصميم كائنات مكتبية مثل كتاب وقائمة ورف، بل وأيضا كائنات ذات عوالم أخرى بَيْدَ أنها قد تتعلق بالمكتبة من جهة أو من أخرى كتلميذ ومدرس.

من أجل هذا، نحتاج للتفكير قبل البدء، التفكير في الكائنات التي سنحتاجها، في خصائصها ووظائفها والعلاقات فيما بينها، وهذا لا يكون سهلا لأن صناعة كون برمجي متماسك ومنظم يتطلب تحليلا وتصميما مُرَكزا قبل البدء العبثي في التكوين والبرمجة.

هذا الموضوع يضم معلومات من أجل اكتساب مهارات التحليل والتصميم للأكوان البرمجية، وهذا الجزء الأول هو تمهيد وتحفيز لما يليه من الأجزاء.

1. قبل البدء


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

2. التحليل والتصميم


التحليل هو التحقيق في كل مايتطلبه مشكل ما دون البحث عن الحل، فقط تحديد المتطلبات والإحاطة بالمشكل وفهمه جيدا.

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

3. لغة النمذجة الموحدة


هي طريقة قياسية وموحدة تحدد كيفية رسم النماذج والرسوم التي تعبر عن الكون البرمجي الذي نريد صنعه، وهي تضم رسومات منها ما يختص بوصف السياق العام للكون وأخرى تصف الكائنات والعلاقات فيما بينها، ورسومات أخرى سنتعلمها لاحقا.

الان ونحن أمام مشكل ما، نعلم أنه يجب علينا البدء بالتحليل والتصميم، وأن النتائج يتم التعبير عنها بواسطة لغة النمذجة الموحدة، ولكن السؤال المحوري هو كيف؟ كيف أحلل وأصمم؟ ما الخطوات التي يجب اتباعها؟ من أين أبدء و إلى أين أنتهي؟ ماذا أفعل وماذا لا أفعل؟ سلسلة الأسئلة طويلة ولَها وُضعت مناهج عديدة يمكن إتباعها، من أشهرها المنهج المُوحَد.

4. المَنهج الموحد


عموما، منهج برمجة هو نهج نتبعه من أجل بناء وبرمجة وصيانة نظام برمجي ما، يشتهر المنهج الموحد عن باقي المناهج بنظرية التطوير بالدورات.

1.4. التطوير بالدورات


تُقَسَمُ عملية التطوير إلى دورات مدتها الزمنية قصيرة نسبيا (4 أسابيع في كل دورة مثلا)، وكل دورة تعتبر مشروعا صغيرا بداته، عند نهاية كل دورة، تكون النتيجة إصدارا جزئيا للبرنامج، قابلا للإشتغال والتنفيذ، كل دورة تتضمن أنشطة التحليل والتصميم والبرمجة والتجريب الخاصة بها.

يتمحور هذا النمط من التطوير البرمجي حول فكرة التطوير المتدرج للنظام، بحيث نقوم بتكبير وصقل النظام تدريجيا وعبر العديد من الدورات، ينمو النظام بشكل تدريجي ودوري بمرور الوقت، دورة بعد دورة، حتى يكتمل النظام ويصبح جاهزا للإصدار الكامل.

2.4. لماذا التطوير بالدورات؟


من الناس من يقوم بتحديد المتطلبات وتحليلها تُم تصميم النظام بشكل كامل، شامل ونهائي، بحيث أنه، أثناء التطوير وكتابة الأكواد، يتفادى ما أمكنه التعديل والتبديل في التصميم، وهذا المنهج جيد إلا أنه مستحيل، فكثيرا ما أدركنا احتياجنا لكائن أو علاقة أو خاصية ما أثناء البرمجة ولم نفكر فيها يوم قمنا بالتصميم، وزيادة الأشياء حسب الحاجة قد يؤثر سلبا على تماسك النظام، إذ أنه في كل زيادة أو نقصان يجب إعادة التفكير في التصميم الكلي للنظام وهذا أمر متعب يذهب بمتعة البرمجة ويجعل منها عقابا يضرب له ضربا وحسابا.

في التطوير بالدورات، في كل دورة نختار مجموعة صغيرة من المتطلبات، نصممها، نبرمجها ونجربها. ففي الدورات المبكرة من المشروع، قد تكون المتطلبات غير دقيقة، ولكننا نصقلها دورة بعد دورة، وذلك إعتمادا على تجريب الإصدارات الجزئية للنظام وكذلك اَراء المطورين والمستعملين له.

أكثر من ذلك، فعوض شق الرأس في البحث عن المتطلبات الدقيقة والتصميم الكامل والمثالي، فإن التنفيذ والتجريب الواقعي للبرنامج يعطي فكرة أوضح حول ما يجب فعله من حيث تحديد المتطلبات والتصميم. فالمستعمل تكون له فرصة ليرى إصدارا جزئيا بعينه ويقول: نعم هكذا أريده، والاَن وقد جربته، فبصراحة أريده أن يكون كذا وكذا. وهذا يكون أفضل من التعب على نظام لا يجده المستعمل عمليا بالنسبة إليه، فنحن لا نستطيع الإعتماد على تخيلات المستعمل فهي غالبا ما تكون بعيدة على ما يحتاجه هو حقا، فبإعطائه الفرصة للتجريب تصبح متطلباته أكثر واقعية ووضوحا.

5. بعض المصطلحات المتعلقة بالمنهج الموحد


1.5. فترات التطوير


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

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

2.5. التخصصات، الأنشطة والنواتج


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


تخصصات المنهج الموحد

6. كيف يعمل كل هذا؟


في جعبتنا خمسة مفاهيم (الدورات، الفترات، التخصصات، الأنشطة والنواتج)، نعلم أنها كلها تتعلق بالمنهج الموحد لكن كيف نعمل بها جميعا في سبيل اتباع هذا المنهج؟

التخصصات والفترات في المنهج الموحد

يمر كل مشروع من أربع فترات (البدء، الإعداد..)، تُقسم كل فترة إلى عدة دورات (ثلاث، اربع أو بضع عشرات)، في كل دورة نعمل على عدة تخصصات (نمذجة الأعمال، المتطلبات..). فمثلا في الدورة السابعة من فترة الإعداد، نقوم بنمذجة الأعمال ثم المتطلبات والتصميم فالإنجاز والتجريب، وفي نهاية الدورة يكون لدينا برنامج جزئي قابل للتنفيذ والإشتغال، نعمل على تطويره أكثر في الدورة الثامنة من فترة الإعداد وهكذا.

7. ماذا بعد؟


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

على أي ما سنتعلمه هو كالتالي:

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

1. تحليل المتطلبات.
2. أساسيات تحليل وتصميم الكون البرمجي، وتحديد أدوار الكائنات.
3. تصميم الأكوان باستعمال بعض قوالب التصميم.
4. قد نتكلم عن كيفية تصميم بيئة عمل لعدم البدء في كل مرة من الصفر.

نُكمل إن شاء الله في تدوين قادم.
والله أعلم.


أكمل القراءة