اذهب إلى المحتوى

كل الأنشطة

تحدث تلقائيًا

  1. الساعة الماضية
  2. الخطأ بسيط ورسالة الخطأ توضح أنك قمت بفتح قوس معقوف { في السطر 72 أي: if(isset($_POST['login'])){ لكنك لم تقم بإغلاقه بعدها، فمفسر اللغة لم يجد قوس الإغلاق فأعطى الخطأ. يُفترض منك إضافة القوس في الأخير: if(isset($_POST['login'])){ } حاول دائما إحترام المسافة البادئة في الكتل البرمجية قبل سطر الكود لتجنب الوقوع في هذه المشاكل كما هو موضح في الصورة:
  3. اليوم
  4. في حال عملك مع لغة بايثون تأكد من تثبيت بايثون من الموقع التالي link ومن ثم تثبيت الامتداد الخاص بها في البرنامج كما يلي: تاكد عند فتح البرنامج الخاص فيك قم بفتح المجلد باكمله ليس فقط ملف واحد بشكل مباشر وتاكد من ان نهاية الملف py.
  5. في البداية يوجد خطأ عند تطبيقك الخط على محتويات الجدول أي عند انشاء كائن من الـTableStyle: ('FONTNAME', (0, 0), (-1, -1), 'Arabic') بهذا تكون قد حلت مشكلة عدم فهم وتشفير اللغة العربية أما بالنسبة للأرقام فيمكنك إنشاء التابع البسيط التالي للتحويل: def convert_to_arabic(number): arabic_digits = { '0': '٠', '1': '١', '2': '٢', '3': '٣', '4': '٤', '5': '٥', '6': '٦', '7': '٧', '8': '٨', '9': '٩' } arabic_number = '' for digit in number: if digit.isdigit(): arabic_number += arabic_digits[digit] else: arabic_number += digit return arabic_number ومن ثم استخدامه بالشكل التالي: reshaped_data = [ [ get_display(reshape(convert_to_arabic(cell))) for cell in row ] for row in mydata ] لتظهر النتيجة بالشكل التالي وتم ارفاق الكود كامل في المرفقات وتأكد من تنزيل المكاتب التالية قبل التشغيل : pip install reportlab pip install arabic_reshaper pip install python-bidi arabic_tables.py
  6. يوجد اصدارين من PyTorch اصدار يعمل على CPU واصدار على ال GPU ويعتمد نوع الاصدار الذي تريده الى نوع الخدمات التي تريد ان تعمل عليها فهناك نماذج تحتاج الى عمليات كبيرة لذلك تتطلب للتشغيل GPU. فان PyTorch هو إطار عمل مفتوح المصدر للتعلم العميق طور الإطار من قبل فريق بحث الذكاء الاصطناعي في شركة ميتا (فيسبوك سابقًا) عام 2016 استنادًا إلى مكتبة تورش Torch المستندة بدورها إلى لغة البرمجة Lua. اي قامو بجعل الخدمات التي تقدمها Torch تقدم بلغة بايثون فاصبحت PyTorch اي Py هي لتبيان انها النسخة التي تعمل بلغة بايثون نظرا لقوة وشهرة بايثون في تطوير نماذج الذكاء الاصطناعي. لتثبيت PyTorch نسخة ال cpu : pip3 install torch torchvision torchaudio لتثبيت PyTorch نسخة ال GPU : تحتاج اولا الى برنامج للتاخطب مع GPU حيث ان GPU الخاصة بشركة NVIDIA تعطينا برنامج يدعى CUDA يقوم بالتخاطب مع ال GPU وتجعل الGPU يقوم بالعمليات على التوازي مما يسرع من اتمام العمليلت اسرع من انجازها على GPU ولتسطيع PyTorch التخاطب وتنفيذ عملياتها لتثبيت CUDA: ملاحظة يجب ان يكون جهازك يملك GPU ذات قدرات عالية اقل شي GTX 1050 لتتمكن من العمل على جهازك. تثبيت (++Visual C) لان CUDA مبني على لغة (++c) ويحتاج بعض المكاتب عند تثبيته على حاسوبك الدخول الى الموقع التالي واختيار النسخة المناسبة لك حسب جهاز الحاسب الخاصة بك. الدخول الى موقع NVIDIA 3. ثم تثبيت CuDNN وهي عبارة عن مكاتب تدعم عمل البرنامج : تثبيت PyTorch من موقع الرسمي : حسب النسخة المتوافقة مع CUDA التي قمت بتحميلها مثال للنسخة 12.1 ويجب ملاحظة ان بعض النسخ قد لا تكون متوفرة بعد فيPyTorch لذلك نطر للعودة لنسخ اقدم من CUDA pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 وبنسبة للفرق بين pip و conda : pip : هو اداة لادراة المكاتب و التنزيلات والحزم الخاصة بلغة بايثون تكون موجودة بشكل افتراضي عندد تنزيل اللغة. conda: هي نظام او برنامج يقوم بادراة افضل للمكاتب والحزم الخاصة بلغة بايثون خاصة للاشخاص المبتدئين لانها تقوم بتنزيل جميع المكاتب والادوات المشهورة التي تستعمل في بغة بايثون ويمكن تنزيلها عبر الرابط التالي linl
  7. مساحة (عرض) العنصر الأب صغيرة إذن، أو عرض المنتجات كبيرة على المساحة، لذا عليك تحديد مساحة الثلث لكل منتج من خلال التنسيق التالي للكلاس الخاص بالمنتجات: flex-basis: 33.3333% وهو إختصار للخواص التالية: flex-grow: 0 flex-shrink: 0 flex-basis: 33.3333%
  8. المشكلة تبدو أنها تكمن في دالة `askStudentID` وبناء على الكود المقدم ووصف المشكلة فعندما يدخل المستخدم رقم تعريف الطالب، يتم استدعاء دالة `askStudentID` متكررا حتى يدخل رقم تعريف طالب صالح فبعد إدخال رقم تعريف طالب صالح، لا تستمر الدالة إلى الخطوة التالية من استرجاع معلومات الدرس وتسجيل الطالب. لحل هذه المشكلة، تحتاج إلى تعديل دالة `askStudentID` للتعامل مع حالة رقم تعريف الطالب الصالح والمتابعة مع الخطوات التالية وهذا هو الكود المعدل: function askStudentID(){ rl.question('ادخل رقم الطالب: ', student_id=>{ if(student_id.trim() == '' || isNaN(student_id)){ console.log('يرجى إدخال أرقام فقط'); askStudentID(); }else{ dataBase.get(`SELECT * FROM students WHERE student_id = ${student_id}`, (err, rowStudent)=>{ if(err){ rl.close(); dataBase.close(err=>{ if(err) return console.log(err.message); else return console.log('تم إغلاق قاعدة البيانات.'); }) return console.log(err.message); }else if(rowStudent){ // المتابعة إلى الخطوة التالية لاسترجاع معلومات الدرس وتسجيل الطالب console.log('تم العثور على رقم الطالب.'); // الجزء الباقي من الكود لاسترجاع معلومات الدرس وتسجيل الطالب }else{ console.log('رقم الطالب غير موجود.'); askStudentID(); } }) } }) } فهنا قد قم بإدخال رقم تعريف طالب صالح، سيحتوي متغير `rowStudent` على معلومات الطالب. يمكنك استخدام هذه المعلومات للمتابعة مع الخطوة التالية من استرجاع معلومات الدرس وتسجيل الطالب وهذا الإجراء يجب أن يمنع الكود من الخروج من دالة `askStudentID` مبكرا ويسمح له بالمتابعة مع بقية عملية التسجيل.
  9. شكرا علي الرد لم استطيع فهمه ممكن شرح علي يوتيوب تنصحني بيه
  10. نعم ذلك صحيح وهو ما يعرف بالاستيثاق يمكنك التعمق به اكثر من خلال هذه الدروس والمقالات https://wiki.hsoub.com/Laravel/authentication https://io.hsoub.com/laravel/100860-ال-auth-في-laravel و بالتوفيق لك
  11. أرجو الإنتظار وسيتم الرد عليك من قبل مركز المساعدة في أقرب وقت، فقد تم إرسال مشكلتك إليهم، وسأعود إليك إن كان هناك أمر عليك فعله.
  12. كيف يمكنني الوصول الى بطاقة الدعم الفني الخاصة بي التي كنت اراسل المدرب الذي يتولى متابعة الامتحان الخاص بي من خلالها , حاولت الوصول اليها من الجيميل وكل ما اضغط على زر رؤية المحادثة كاملة يأخذني الى انشاء بطاقة جديدة. وقد كان اوصاني المدرب ان اقوم بارسال الكود والتعديلات عليها وان لا اقوم بفتح بطاقة دعم جديدة.
  13. بالنسبةللإلتزامات قصيرة الأجل، فيجب على الشركة سدادها خلال سنة واحدة أو دورة التشغيل العادية، وتشمل أمثلة ذلك الحسابات الدائنة، وأوراق الدفع، والقروض قصيرة الأجل، والمصروفات المستحقة. والالتزامات طويلة الأجل هي الالتزامات التي تستحق الدفع بعد سنة واحدة من تاريخ الميزانية العمومية، مثل القروض طويلة الأجل، والسندات، والالتزامات الاستئجارية. تُدرج الالتزامات قصيرة الأجل وطويلة الأجل في قسم الخصوم في الميزانية العمومية. وللحصول على القيمة الدفترية للالتزامات قصيرة الأجل، عليك جمع جميع المبالغ المدرجة في قسم الخصوم المتداولة، أما القيمة الدفترية للالتزامات طويلة الأجل قم جمع جميع المبالغ المدرجة في قسم الخصوم طويلة الأجل.
  14. في php لمعرفة صلاحيات مستخدم نستخدم جلسات session اما في إطار عمل لارافيل ماذا نستخدم الحظ بعض يستخدم كلاس يسمي Auth
  15. عليكي استخدام flex box، ثم تعيين flex-wrap لكي يتم عرض المنتجات الباقية أسفل المنتجات الأخرى عندما لا توجد مساحة في العنصر الأب، أي يتم إزاحتها على سطر جديد. أي تعيين التالي للعنصر الأب الذي يحتوي المنتجات: .wrapper{ display: flex; flex-wrap: wrap; gap: 10px; } ثم وضع المنتجات بداخله، وكل منتج يجب أن يكون بداخل div منفصل.
  16. السلام عليكم ، لماذا يقوم بالخروج من سطر الأوامر عندما أقوم بإدخال الstudent id ولا يتابع بقية الشيفرة في الجزء الخاص بعندما يقوم المستخدم بإدخال حرف r script.js
  17. مشكلة اختفاء العناصر قد تكون بسبب تموضع العناصر، لهذا تأكد من أن جميع العناصر موضوعة داخل حدود التخطيط الصحيحة، مثل ConstraintLayout أو LinearLayout، ومن خصائص العرض مثل ال visibility و layout_width و layout_height فيجب أن تكون مضبوطة بشكل صحيح. لا يمكن تحديد المشكلة بالتحديد، لهذا إن لم يعمل معك فيمنك القيام بتنظيف ملفات ذاكرة التخزين المؤقت يمكن ذلك من خلال الانتقال إلى: File > Invalidate Caches / Restart. وفي بعض الأحيان، يمكن أن يؤدي إعادة تشغيل أندرويد ستوديو إلى حل المشكلة أو تحديثه. أما بالنسبة لمشكلة عدم كتابة التعليمات البرمجية التي واجهتك، تأكد من أن لوحة المفاتيح مضبوطة على اللغة الصحيحة وأن جميع الاختصارات تعمل بشكل صحيح. قد يكون بسبب مشكلة في التحديثات، لذا تأكد من أنك تستخدم أحدث إصدار من أندرويد ستوديو. انتقل إلى: File > Settings > Appearance & Behavior > System Settings > Updates للتحقق من وجود تحديثات، إذا لم تنجح الحلول الأخرى، فحاول إعادة تثبيت أندرويد ستوديو لكن تأكد من حذف جميع المجلدات والملفات المتعلقة بأندرويد ستوديو قبل إعادة التثبيت.
  18. ابيه يطلع نفس الموقع الي تحت بنجب بعض صورت الcss
  19. أولا في حالة ما كانت لديك شركة، فستحتاج إلى الرجوع إلى الميزانية العمومية للشركة، وتحديد حسابات الالتزامات قصيرة الأجل وطويلة الأجل، ثم جمع الأرصدة، والوصول في النهاية إلى القيمة الدفترية. فحينما تقوم بتحديد تلك الالتزامات في القائمة المالية سيتم استخدام القوائم المالية لحساب القيمة الدفترية، والتي تتطلب القيام بالخطوات التالية: تحليل القوائم المالية: من خلال فحص البيانات المالية الخاصة بالشركة، مثل البيانات الدورية (مثل بيان الدخل والميزانية العمومية) وبيان التدفقات النقدية. تحديد الالتزامات الطويلة والقصيرة الأجل: هنا نقوم بتحديد الالتزامات التي تعتبر طويلة الأجل (أي تلك التي تستحق فترة تزيد عن سنة واحدة) والالتزامات القصيرة الأجل (تستحق فترة أقل من سنة). حساب القيمة الدفترية: لحساب القيمة الدفترية للالتزامات، من خلال جمع قيمة الالتزامات الطويلة والقصيرة الأجل وهنا يجب أن تكون الأرقام المستخدمة في هذا الحساب مبينة في القوائم المالية الخاصة بالشركة. التأكد من الدقة: من أجل التأكد من أن البيانات التي تم استخدامها لحساب القيمة الدفترية دقيقة وموثوقة. يمكن أن يتم التحقق من القوائم المالية والتقارير الخاصة بالشركة نفسها. وبمجرد حساب القيمة الدفترية، يمكن استخدام هذه المعلومات لتقييم حالة التمويل الخاصة بالشركة وفهم كيفية توزيع الالتزامات على المدى الطويل والقصير، لكن يجب أن ننوّه بأنّ القيمة الدفترية للالتزامات ليست القيمة الفعلية التي يتم دفعها، وإنما تمثل القيمة المحاسبية لهذه الالتزامات في وقت معين.
  20. ال "methods chaining" أو "سلسلة الدوال" هو عبارة عن أسلوب يتيح لنا استدعاء سلسلة من الدوال على كائن واحد دون الحاجة إلى تخزين النتيجة بين كل استدعاء، وفي إطار العمل Laravel نجد أن العديد من الدوال ترجع `$this`، وهذا يعني أنها تعود بالكائن نفسه بعد الانتهاء من تنفيذ الدالة، مما يسمح بمواصلة استدعاء الدوال الأخرى على الكائن نفسه بسلاسة.أما بخصوص العلامة "::" في PHP، فهي تستخدم لاستدعاء الدوال الثابتة (static methods) والثوابت (constants) من داخل الصنف (class) بدون الحاجة لإنشاء كائن من الصنف، انظر لهذا المثال: class MyClass { public static function myStaticMethod() { return "Laravel"; } } echo MyClass::myStaticMethod(); // سيطبع "Laravel" وأما بالنسبة لعملية "->" فهي تستخدم للوصول إلى خصائص الكائنات (properties) والدوال ضمن الكائنات (methods)، أو للوصول إلى العناصر في مصفوفة، يمكن أن يتضح الأمر أكثر من خلال هذا المثال: class MyClass { public $name = "Hsoub"; public function greet() { return "Hi, " . $this->name; } } $obj = new MyClass(); echo $obj->greet(); // سيطبع "Hi, Hsoub" في حين "->" فهي تستخدم للإشارة إلى أن الدالة تعمل على كائن (Object) معين.
  21. هناك أسباب كثيرة تجعلنا نستخدم methods chaining ومنها : يسهل methods chaining فهم تتابع الكود وقراءته بشكل افضل ويجعل الكود أكثر سلاسة وسهولة اثناء التعديلات مستقبلا . في بعض الاوقات تحسن methods chaining من أداء التطبيق بشكل عام، على سبيل المثال يمكن تجنب تحميل البيانات من قاعدة البيانات بشكل متكرر عند استخدام الـ eager loading فيLaravel وبهذا ستحصل على سرعه واداء فاضل اثناء عمل التطبيق . ليس بالضرورة ذلك يمكنهم ارجاع قيم مختلفة كما في هذا المثال الخاص بتسجيل الدخول والذي يقوم بأرجاع قيمة منطقية او قيمة public static function isLoggedIn($userId) { $user = User::find($userId); if ($user) { return $user->is_logged_in; } return false; } علامة (::) تمسى (scope resolution operator) تستخدم للوصل الى الدوال والمتغيرات داخل الكلاس كما في المثال التالي : class MyClass { const MY_CONSTANT = 10; public static function myFunction() { return "Hello"; } } echo MyClass::MY_CONSTANT; echo MyClass::myFunction(); اولا قمنا باستخدامه للوصول الى الثابت MY_CONSTANT الموجودة داخل الكلاس MyClass ثم استخدمناه ايضا لاستدعاء الدالة myFunction الموجودة في الكلاس MyClass و ماهو -> arrow operator يستخدم للوصول إلى الخصائص والدوال لكائنات الكلاس كمثال class Person { public $name; public function sayHello() { return "Hello, my name is " . $this->name; } } $person = new Person(); $person->name = "John"; echo $person->sayHello(); // يُطبع "Hello, my name is John" اولا استخدمناه للوصول الى الخاصية name وتعيين القيمة John لها ثم استخدمناها ايضا لاستدعاء الدالة sayHello الموجودة في الكلاس Person بالتوفيق لك
  22. السلام عليكم ورحمة الله وبركاته لماذا اغلب استعمال إطار عمل لارافيل عبارة دوال مربوطه ببعضها methods chaining هل كلهم عبارة انه يرجعو return $this ممكن شرح colon في php :: عبارة عن نقطتين وراء بعض و ماهو -> arrow operator
  23. كيف استخرج القيمة الدفترية للالتزامات طويلة وقصيرة الاجل؟
  24. سلام عليكم أنا اواجه مشكلة في اندرويد استيديو نسخة 2021.3.17 عندما اضع العناصر مثل button او اي من العناصر الأخرى تختفي الواجهة ولا يوجد سبب لأختفاءها وبعدها نزلت نسخة 2023 لا استطيع كتابة الأكواد رجاء جاوبوني عن هذه المشكلة
  25. البرمجة كائنية التوجه Object-Oriented programming واختصارًا OOP هي مصطلح برمجي أساسي في الكثير من لغات البرمجة مثل جافا و ++C. ونحاول في هذا المقال تزويدك بإحاطة شاملة عن أساسيات مفهوم البرمجة كائنية التوجه، ونشرح مفاهيمها اﻷساسية، ونوضح مفهوم اﻷصناف classes والنسخ instances والوراثة inheritance والتغليف encapsulation. ولن نخص في شرحنا لهذه المفاهيم لغة جافا سكريبت حاليًا، وستكون اﻷمثلة جميعها مكتوبة بلغة معممة (أو بالشيفرة الوهمية pseudo-code). ملاحظة: لتوخي الدقة، عليك معرفة أن ما سنشرحه هو نمط مخصص من البرمجة كائنية التوجه هو البرمجة كائنية التوجه التقليدية. وهو المصطلح المقصود عندما يجري الحديث عمومًا عن البرمجة كائنية التوجه. بعد ذلك، سنوضح العلاقة بين الدوال البانية constructor وكائنات prototype في جافا سكريبت وبين مفاهيم البرمجة كائنية التوجه التي أشرنا إليها سابقًا، وأبرز الاختلافات بينها. وسنركز في مقالات لاحقة على بعض الميزات اﻹضافية في جافا سكريبت التي تساعد على تنفيذ برامج كائنية التوجه. ننصحك قبل أن تبدأ العمل معنا في هذه السلسلة أن تطلع على: أساسيات جافا سكريبت كما شرحناها في سلسلة المقالات السابقة. أساسيات البرمجة كائنية التوجه في جافا سكريبت، كما شرحناها في مقال أساسيات العمل مع الكائنات في جافا سكريبت، ومقال استخدام كائنات Prototype في جافا سكريبت. ما هي البرمجة كائنية التوجه تشير البرمجة كائنية التوجه إلى طريقة لنمذجة نظام على شكل مجموعة من الكائنات، يمثّل كل كائن بعض ميزات النظام. وتضم الكائنات دوال functions أو (توابع methods) وبيانات data، كما يقدّم الكائن واجهة عمومية تستخدمها كائنات أو شيفرات أخرى للتعامل معه وواجهة خاصة تحتفظ بمعلومات وبيانات عن الحالة الداخلية للكائن ولا يمكن التعامل معها من خارج الكائن أي أنها تكون غير مرئية لما هو خارج الكائن، وبالتالي لن تُضطر بقية أجزاء المنظومة إلى معرفة ما يجري داخليًا ضمن أجزاء أو كائنات أخرى. اﻷصناف Classes والنُّسَخ Instances عندما نريد نمذجة مسألة وفقًا لمبدأ البرمجة كائنية التوجه OOP، ننشئ تعريفات عامة تمثّل أنواع الكائنات التي نريدها في المنظومة. فلو أدرنا مثلًا نمذجة مدرسة، قد نرغب بإنشاء كائنات تمثل المدرّسين، ويكون لهؤلاء المدرسين ميزات أو سمات مشتركة كأن يكون لهم أسماء ومواد يدرّسونها. وإضافة إلى ذلك، يمكن لأي مدرس تنفيذ أعمال محددة، مثل تصحيح اﻷوراق أو تقديم أنفسهم إلى الطلاب في بداية العام الدراسي مثلًا. لهذا يمكن أن يكون المدرّس ضنفًا في المنظومة باسم Professor، ويٌعرّف الصنف بداخله مجموعة من البيانات والتوابع التي يمتلكها كل مدرّس في المدرسة. على سبيل المثال يمكن أن يُعرّف الصنف Professor بالشيفرة الوهمية التالية: class Professor properties name teaches methods grade(paper) introduceSelf() تُعرّف الشيفرة السابقة الصنف Professor كالتالي: خاصيتين أو سمتين تحملان بيانات المدرس وهما name التي تمثل اسم المدرس و teaches التي تمثل المواد التي يقوم بتدريسها. تابعين هما ()grade لتصحيح ورقة، و ()introduceSelf للتعريف عن أنفسهم. كما تلاحظ ليس للصنف وظيفة قائمة بحد ذاتها، بل هو أقرب إلى قالب ﻹنشاء كائنات objects من هذا النوع أو الصنف. فكل مدرّس ننشئه وفق القالب Professor يُدعى نسخة instance عن هذا القالب. تُنشأ نسخة عن صنف باستخدام نوع خاص من الدوال تُدعى بالدوال البانية constructors. إذ نمرر قيمًا إلى الدوال البانية لتهيئة النسخة بقيم تضبط حالتها الداخلية اﻷساسية. تُكتب الدوال البانية عمومًا كجزء من تعريف الصنف، ولها عادة نفس اسم الصنف، لاحظ الشيفرة التالية: class Professor properties name teaches constructor Professor(name, teaches) methods grade(paper) introduceSelf() تأخذ الدالة البانية في الشيفرة السابقة معاملين أو وسيطين، لهذا بإمكاننا تهيئة الخاصيتين name و teaches عند إنشاء نسخة جديدة أو كائن عن صنف المدرّس. وطالما أن لدينا دالة بانية اﻵن، سنتمكن من إنشاء بعض المدرسين، وتستخدم بعض لغات البرمجة عادة الكلمة المحجوزة new للإشارة إلى استدعاء الدالة البانية: walsh = new Professor("Ahmad", "Psychology"); lillian = new Professor("Lyla", "Poetry"); walsh.teaches; // 'Psychology' walsh.introduceSelf(); // 'My name is Professor Ahmad and I will be your Psychology professor.' lillian.teaches; // 'Poetry' lillian.introduceSelf(); // 'My name is Professor Lyla and I will be your Poetry professor.' تنشئ شيفرة جافا سكريبت السابقة كائنين، وكلاهما نسخة عن الصنف Professor. الوراثة Inheritance لنفترض أننا نريد إنشاء طلاب في منظومة المدرسة السابقة، لكن لا يمكن للطلاب تصحيح اﻷوراق ولا يمكنهم تدريس مواد، وينتمون إلى سنوات دراسية محددة. لكن سيحمل الطلاب أسماءً، وقد يرغبون بتقديم أنفسهم، لهذا يمكن صياغة صنف خاص الطلاب من خلال الشيفرة الوهمية التالية: class Student properties name year constructor Student(name, year) methods introduceSelf() ومن المفيد أن نشير إلى اشتراك الطلاب والمدرسين ببعض الخاصيات، أو بشكل أدق اﻹشارة إلى أنهما ينتميان إلى نوع واحد عند مستوى ما، وهذا ما تسمح به الوراثة inheritance في البرمجة كائنية التوجه. فقد ننظر إلى المدرسين والطلاب بداية على أنهم أشخاص، وللأشخاص أسماء ويقدموّن أنفسهم عند الحاجة. ولنمذجة هذه الفكرة، ننشئ صنفًا جديدًا هو Person، نعرّف فيه جميع الخصائص المشتركة للأشخاص، ثم باﻹمكان اشتقاق الصنفين Professor و Student من الصنف Person ومن ثم إضافة الخاصيات المميزة لكل صنف: class Person properties name constructor Person(name) methods introduceSelf() class Professor : extends Person properties teaches constructor Professor(name, teaches) methods grade(paper) introduceSelf() class Student : extends Person properties year constructor Student(name, year) methods introduceSelf() وهكذا يمكن القول أن الصنف Person هو صنف أعلى super class أو صنف أب parent class لكل من الصنف Professor والصنف Student اللذان يُدعيان في هذه الحالة بأصناف فرعية sub classes أو أصناف أبناء child class. ولاحظ كيف عُرِّف التابع ()introduceSelf في جميع الأصناف الثلاث، والسبب هو اختلاف الطريقة التي يُقدّم فيها كل صنف نفسه: ahmad = new Professor("Ahmad", "Psychology"); ahmad.introduceSelf(); // 'My name is Professor Ahmad and I will be your Psychology professor.' summers = new Student("Summers", 1); summers.introduceSelf(); // 'My name is Summers and I'm in the first year.' وباﻹمكان أيضًا كتابة تابع افتراضي ()introduceSelf للتعريف عن أشخاص ليسوا طلابًا ولا مدرسين: passam = new Person("Passam"); passam.introduceSelf(); // 'My name is Passam.' تُدعى فكرة وجود تابع بنفس الاسم في عدة أصناف، لكنه ينفّذ وظيفة خاصة في كل صنف بتعدد الأشكال polymorphism، حيث يمكن تعريف تابع بنفس الاسم في الصنف الأب والابن وفي هذه الحالة يحل التابع المعرف في الصنف الابن محل التابع المعرف في الصنف الابن، ونقول في هذه الحالة أننا تجاوزنا overrides نسخة التابع الموجودة في الصنف اﻷب. التغليف Encapsulation تقدّم الكائنات واجهة عامة لبقية الشيفرة كي تتخاطب معها، لكنها تحتفظ بحالتها الداخلية (قيم مخصصة تساعدها على تنفيذ وظائفها). ونقول أن الحالة الداخلية للصنف تبقى خاصة private، أي يمكن الوصول إليها من قبل التوابع الخاصة بالصنف فقط، وليس من قبل أية كائنات أخرى. تُدعى عملية إبقاء الحالة الداخلية للصنف خاصة أو الفصل الواضح بين الواجهة العامة للصنف وأعضاءه الداخليين عمومًا بالتغليف encapsulation. تأتي أهمية هذه الميزة بأنها تسمح للمبرمج بتغيير الواجهة الداخلية للكائن دون الحاجة إلى البحث عن الشيفرة التي تستخدمه وتعديلها. فهي تقدم شكلًا من أشكال جدران الحماية بين الكائن وبقية مكونات المنظومة. فلو سمُح لطلاب السنة الثانية وما فوق دراسة الرماية، باﻹمكان تنفيذ اﻷمر بالاستفادة من الخاصية year، وستتمكن بقية الشيفرة من تحديد إمكانية تسجيل الطالب في صف الرماية أو لا: if (student.year > 1) { // allow the student into the class } لكن المشكلة ستقع إذا غيرنا معيار السماح للطلاب بالتسجيل في درس الرماية، كأن يحتاج إلى موافقة ولي أمره، عندها علينا تغيير الشيفرة التي تتحقق من إمكانية تسجيل الطالب في كل مكان. لهذا من اﻷفضل إنشاء تابع ()canStudyArchery في الكائنات Student لتنفيذ منطق العملية. class Student : extends Person properties year constructor Student(name, year) methods introduceSelf() canStudyArchery() { return this.year > 1 } if (student.canStudyArchery()) { // allow the student into the class } وهكذا، سيكون علينا تغيير الصنف Student فقط إذا أردنا تغيير شروط دراسة الرماية، وستعمل بقية الشيفرة في كل مكان كما يجب. وبامكاننا في الكثير من لغات البرمجة كائنية التوجه منع بقية الشيفرة من الوصول إلى الحالة الداخلية للكائن بجعل خاصياتها private، وسينتج خطأ إن حاولت الشيفرة خارج الصنف الوصول إلى الخاصية: class Student : extends Person properties private year constructor Student(name, year) methods introduceSelf() canStudyArchery() { return this.year > 1 } student = new Student('Wael', 1) student.year // error: 'year' is a private property of Student أما في اللغات التي لا تفرض قيودًا كهذه على الوصول، يستخدم المبرمجون أسلوبًا في التسمية، يميزّون فيه الخاصيات ذات الوصول الخاص، كأن تبدأ التسمية بشرطة سفلية _. تحقيق البرمجة كائنية التوجه في لغة جافا سكريبت ناقشنا حتى اللحظة في مقالنا الميزات اﻷساسية للبرمجة كائنية التوجه بالعموم والتي تعتمدها لغات برمجة عديدة مثل ++C وجافا، وكنا قد ألقينا النظرة في مقالي أساسيات الكائنات في جافا سكريبت وكائنات prototype عن مفهومي الدوال البانية والكائنات prototype. وترتبط هاتان الميزتان بالتأكيد مع ميزات البرمجة كائنية التوجه إلى حد ما. حيث تزوّدنا الدوال البانية في جافا سكريبت بما يشبه تعريف الصنف، مما يساعد على تحديد شكل الكائن، بما في ذلك التوابع التي قد يتضمنها في مكان واحد من الشيفرة. كما يمكن استخدام كائنات prototype أيضًا، فلو عُرِّف تابع مثلًا ضمن الخاصية prototype لدالة بانية، فإن جميع الكائنات التي ننشأها باستخدام الدالة البانية ستمتلك هذا التابع الذي مرر إليها من خلال الكائن prototype، ولا حاجة لتعريفه ضمن الدالة البانية نفسها. كما تبدي سلسلة prototype chain سلوكًا يشبه سلوك الوراثة، فلو كان لدينا كائن من الصنف Student يمتلك الكائن Person ككائن prototype، فسيرث الخاصية name والتابع ()introduceSelf. لكن من المهم أيضًا فهم الاختلاف بين تلك الميزات ومفاهيم البرمجة كائنية التوجه التقليدية. وهذا ما سنناقشه بشيء من التفصيل. بداية، هناك اختلاف واضح في البرمجة كائنية التوجه بين الكائنات واﻷصناف، فالكائنات هي دائمًا نسخ عن اﻷصناف، وهنالك اختلاف واضح بين طريقة تعريف الصنف (الصياغة القواعدية بحد ذاتها) وطريقة إنشاء نسخ عن هذا الكائن (الدالة البانية). بينما نتمكن في جافا سكريبت من إنشاء الكائنات دون الحاجة إلى وجود تعريف مستقل للصنف، سواء عند استخدام الدالة البانية أو بإنشاء الكائن حرفيًا. وهذا ما يجعل العمل مع الكائنات في جافا سكريبت أسرع مقارنة مع البرمجة كائنية التوجه. ثانيًا، على الرغم من أن سلسلة كائنات prototype قريبة من مفهوم الوراثة، وتسلك السلوك نفسه بشكل أو بآخر، لكنهما مفهومان مختلفان. فعند إنشاء كائنات من صنف ابن subclass سنحصل على كائن واحد يجمع بين الخاصيات المعرفة في الصنف الابن والخاصيات المعرّفة في الصنف اﻷب. بينما يتميز نموذج prototyping بأن كل مستوى من مستويات الوراثة الهرمية في سلسلة يمثل بكائن مستقل، وسترتبط هذه الكائنات ببعضها عبر الخاصية _proto_. فالكائنات في سلسلسة prototype chain هي أقرب إلى مفهوم التفويض delegation من مفهوم الوراثة. والتفويض هو نمط برمجي يعطي الكائن القدرة على تنفيذ مهمة ما توكل إليه بنفسه أو تفويض كائن آخر لتنفيذ هذه المهمة. وفي الكثير من اﻷحيان، نرى أن التفويض أكثر مرونة في ربط الكائنات مع بعضها مقارنة بالوراثة (لسبب مهم وهو إمكانية تغيير أو استبدال الكائن المفوَّض كليًا أثناء تنفيذ البرنامج). وهكذا نرى أن الدوال البانية وكائنات prototype هي ميزات تمكننا من تنفيذ أو مقاربة بعض مفاهيم الوراثة كائنية التوجه في لغة جافا سكريبت، لكن استخدامها المباشر في تنفيذ ميزات مثل الوراثة أمر على قدر من الصعوبة. لهذا تقدم جافا سكريبت ميزات مبنية على نموذج كائنات prototype ترتبط بشكل أوضح بمفاهيم الوراثة كائنية التوجه، وهذا ما سنراه بتفصيل أكبر في مقالات لاحقة. الخاتمة تحدثنا في هذا المقال عن الميزات اﻷساسية للبرمجة كائنية التوجه OOP وطريقة تحقيقها في جافا سكريبت، كما ألقينا نظرة سريعة على مواطن الشبه بين الدوال البانية وكائنات prototype في جافا سكريبت وبين مميزات البرمجة بالكائنات. ترجمة-وبتصرف- للمقال Object-Oriented programming اقرأ أيضًا المقال السابق: استخدام كائنات Prototype في جافا سكريبت مدخل إلى جافاسكريبت كائنية التوجه (Object-Oriented JavaScript) لغة البرمجة بالكائنات Object-Oriented Programming برمجة الكائنات Objects في جافاسكريبت
  1. عرض المزيد
×
×
  • أضف...