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

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

  1. سامح أشرف

    سامح أشرف

    الأعضاء


    • نقاط

      4

    • المساهمات

      2934


  2. رضوى العربي

    رضوى العربي

    الأعضاء


    • نقاط

      3

    • المساهمات

      114


  3. Wael Aljamal

    Wael Aljamal

    الأعضاء


    • نقاط

      3

    • المساهمات

      6975


  4. شرف الدين حفني

    • نقاط

      2

    • المساهمات

      1690


المحتوى الأكثر حصولًا على سمعة جيدة

المحتوى الأعلى تقييمًا في 11/06/21 في كل الموقع

  1. لدي قاعدة بيانات مخزن فيها معلومات عن المنتج ومسار الصورة , احاول ان اجلب الصورة عبر المسار وثم ارسالها ولكن لا يمكنني ارسالها مع باقي البيانات في ملف جيسون
    2 نقاط
  2. الإصدار 1.0.0

    47102 تنزيل

    يضع هذا الكتاب المُوجز القارئ على أعتاب عالم تصميم تجربة المُستخدمين UX، وهو علم له قواعده وأصوله وأدواته، ويهدف إلى تعريف القارئ المُبتدئ بأساس هذا العلم وكيف يُطبّق على المُنتجات الرّقمية من مواقع ويب خدميّة وتطبيقات على الأجهزة الذّكية وصولًا إلى التّصميم الأمثل الّذي يُوفِّق بين هدف المُستخدم أوّلًا وهدف الخدمة التّجاريّ، الأمر الّذي يعني منتجًا ناجحًا. يبدأ الكتاب بشرح مفاهيم عامة عن تجربة المستخدم ليواصِل مع شرح كيفية إجراء مختلف الدراسات التي يحتاج المصمِّم للقيام بها، ومتطلباتها، ثم الأمور الواجب أخذها بالحسبان عند التصميم لضمان تجربة استخدام مريحة وممتازة، ليختتم في النهاية بالإشارة إلى أهمية الإحصائيات وضرورة الاعتماد عليها، حيث خُصّصت عدة أقسام لهذه النقطة، لتشير إلى مدى أهمية اعتماد بيانات وإحصائيات المستخدمين مثل أساس للتصميم، وكذا أبرز الإحصائيات الممكن التحصل عليها من خلال عدة اختبارات. يمكنك قراءة فصول هذا الكتاب مباشرةً على شكل مقالات، وإليك العناوين: مدخل إلى تجربة المستخدم User Experience فهم ودراسة المستخدمين في مجال تجربة المستخدم دراسة الشريحة المستهدفة في مجال تجربة المستخدم كيفية التصميم للأجهزة المختلفة هندسة المعلومات في تجربة المستخدم تعرف على أنماط التصميم في مجال تجربة المستخدم أشياء لا يمكن اعتبارها رسوما تخطيطية (Wireframes) في مجال تجربة المستخدم تعرف على الرسوم التخطيطية (Wireframes) في مجال تجربة المستخدم مفهوم الثقل المرئي (Visual Weight) والألوان في مجال تجربة المستخدم التكرار ومخالفة الأنماط في مجال تجربة المستخدم المحاذاة والقرب في مجال تجربة المستخدم تعرف على أساليب مسح الواجهة والتراتب المرئي في مجال تجربة المستخدم أساليب الإطلاع في مجال تجربة المستخدم: التصفح، البحث والاكتشاف تصميم هيكل صفحة الويب والعناصر الأساسية في مجال تجربة المستخدم الأزرار، النماذج والدعوات إلى الإجراء في مجال تجربة المستخدم استخدام علم النفس في مجال تجربة المستخدم لتكييف المستخدم وإقناعه كيف تغير الخبرة من تجربة المستخدم؟ تصميم تجربة المستخدم من خلال بيانات وإحصائيات المستخدمين تعرف على أنواع المخططات الإحصائية في مجال تجربة المستخدم اختبارات أ/ب (A/B Test) في مجال تجربة المستخدم
    1 نقطة
  3. تَسمَح بعض اللغات البرمجية كائنية التوجه (object-oriented programming)، مثل C++‎، للصَنْف بأن يَتمدَّد (extend) من أكثر من مُجرّد صَنْف أعلى (superclass) واحد، وهو ما يُعرَف باسم الوراثة المُتعدّدة (multiple inheritance). بالرسم التالي مثلًا، يَتمدَّد الصنف E من صنفين أعليين (superclasses) مباشرةً، هما الصنفين A و B، بينما يَتمدَّد الصنف F من ثلاثة أصناف أعلين (superclasses) مباشرةً: أراد مُصمِّمي الجافا أن يجعلوا اللغة بسيطة على نحو معقول، ولمّا وجدوا أن مزايا الوراثة المُتعدّدة (multiple inheritance) لا تَستحِقّ ما يُقابِلها من تعقيد مُتزايد، فإنهم لم يُدعِّموها باللغة. ومع هذا، تُوفِّر الجافا ما يُعرَف باسم الواجهات (interfaces) والتي يُمكِن اِستخدَامها لتحقيق الكثير من أهداف الوراثة المُتعدّدة. لقد تَعرَّضنا -بالقسم ٤.٥- لواجهات نوع الدالة (functional interfaces) وعلاقتها بتعبيرات لامدا (lambda expressions)، ورأينا أنها تُخصِّص تابعًا (method) وحيدًا. في المقابل، يُمكِن للواجهات (interfaces) أن تَكُون أكثر تعقيدًا بمراحل كما أن لها استخدامات آخرى كثيرة. من غَيْر المُحتمَل أن تحتاج إلى كتابة واجهات (interfaces) خاصة بك حاليًا؛ فهي ضرورية فقط للبرامج المُعقَّدة نسبيًا، ولكن هنالك عدة واجهات (interfaces) مُستخدَمة بحزم جافا القياسية (Java's standard packages) بطرائق مُهِمّة وتحتاج إلى تَعلُّم طريقة اِستخدَامها. تعريف الواجهات (interfaces) وتنفيذها (implementation) لقد تَعرَّضنا لمصطلح "الواجهة (interface)" ضِمْن أكثر من سياق، سواء فيما يَتَعلَّق بالصناديق السوداء (black boxes) في العموم أو فيما يَتَعلَّق بالبرامج الفرعية (subroutines) على وجه الخصوص. تَتكوَّن واجهة أي برنامج فرعي (subroutine interface) من اسمه، ونوعه المُعاد (return type)، وعدد مُعامِلاته (parameters) وأنواعها. تُمثِل تلك المعلومات كل ما أنت بحاجة إلى مَعرِفته لكي تَتَمكَّن من استدعاء البرنامج الفرعي. بالإضافة إلى ذلك، يَمتلك أي برنامج فرعي جزءًا تّنْفيذيًا (implementation)، هو كتلة الشيفرة المُعرِّفة له (defines) والتي تُنفَّذ عند استدعاءه. بلغة الجافا، كلمة interface هي كلمة محجوزة تَحمِل معنًى تقنيًا إضافيًا. وفقًا لهذا المعنى، تَتكوَّن الواجهة من مجموعة من واجهات توابع النُسخ (instance method interfaces) بدون أجزائها التّنفيذية (implementations). يستطيع أي صنف أن يُنفِّذ (implement) واجهة معينة بتوفير الأجزاء التّنْفيذية (implementation) لجميع التوابع المُخصَّصة ضِمْن تلك الواجهة. اُنظر المثال التالي لواجهة (interface) بسيطة جدًا بلغة الجافا: public interface Strokeable { public void stroke(GraphicsContext g); } تبدو الشيفرة بالأعلى مشابهة لتعريف صنف (class definition) باستثناء حَذْف الجزء التّنْفيذي (implementation) للتابع stroke()‎. إذا أراد صنف معين أن يُنفِّذ تلك الواجهة Strokeable، فلابُدّ له من أن يُوفِّر جزءًا تّنْفيذيًا للتابع stroke()‎ كما قد يَتَضمَّن أي توابع أو متغيرات آخرى. اُنظر الشيفرة التالية على سبيل المثال: public class Line implements Strokeable { public void stroke(GraphicsContext g) { . . . // ارسم خطًا } . . . // توابع ومتغيرات وبواني آخرى } لكي يُنفِّذ صنف واجهةً (interface) معينةً، ينبغي عليه أن يَفعَل أكثر من مُجرّد توفير الأجزاء التّنْفيذية (implementation) لجميع التوابع ضِمْن تلك الواجهة، فعليه تحديدًا أن يُعلن صراحةً عن تّنفيذه (implements) لتلك الواجهة باستخدام الكلمة المحجوزة implements كالمثال بالأعلى. لابُدّ لأي صنف حقيقي (concrete class) يَرغَب بتّنْفيذ الواجهة Strokeable من أن يُعرِّف تابع نسخة اسمه stroke()‎، لذا سيَتضمَّن أي كائن (object) مُنشَئ من هذا الصنف التابع stroke()‎. يُعدّ الكائن مُنفِّذًا (implement) لواجهة معينة إذا كان ينتمي لصنف يُنفِّذ (implements) تلك الواجهة، فمثلًا، يُنفِّذ أي كائن من النوع Line الواجهة Strokeable. في حين يستطيع الصنف أن يَتمدَّد (extend) من صنف واحد فقط، فإنه في المقابل يستطيع أن يُنفِّذ (implements) أي عدد من الواجهات (interfaces). وفي الواقع، يُمكِن للصنف أن يَتمدَّد (extend) من صنف آخر، وأن يُنفِّذ واجهة واحدة أو أكثر بنفس ذات الوقت، لذلك نستطيع كتابة التالي مثلًا: class FilledCircle extends Circle implements Strokeable, Fillable { . . . } على الرغم من أن الواجهات (interfaces) ليست أصنافًا (classes)، فإنها تُشبهها إلى حد كبير. في الواقع، أي واجهة (interface) هي أَشْبه ما تَكُون بصنف مُجرّد (abstract class) لا يُستخدَم لإنشاء كائنات، وإنما كقاعدة لإنشاء أصناف فرعية (subclasses). تُعدّ البرامج الفرعية (subroutines) ضِمْن أي واجهة توابعًا مجردةً (abstract methods)، والتي لابُدّ لأيّ صنف حقيقي (concrete class) يَرغَب بتّنْفيذ تلك الواجهة من أن يُنفِّذها (implement). تستطيع الموازنة بين الواجهة Strokeable والصَنْف المُجرّد (abstract class) التالي: public abstract class AbstractStrokeable { public abstract void stroke(GraphicsContext g); } يَكمُن الفرق بينهما في أن الصنف الذي يَتمدَّد (extend) من الصنف AbstractStrokeable لا يُمكِنه أن يَتَمدَّد من أي صنف آخر. أما الصنف الذي يُنفِّذ الواجهة Strokeable يستطيع أن يَتَمدَّد من أي صنف آخر كما يستطيع أن يُنفِّذ (implement) أي واجهات (interfaces) آخرى. بالإضافة إلى ذلك، يُمكِن لأي صنف مُجرّد (abstract class) أن يَتَضمَّن توابعًا غير مُجرّدة (non-abstract) وآخرى مُجرّدة (abstract). في المقابل، تستطيع أي واجهة (interface) أن تَتَضمَّن توابعًا مُجرّدة فقط، لذا فهي أَشْبه ما تَكُون بصنف مُجرّد نقي (pure). ينبغي أن تُصرِّح عن التوابع ضِمْن أي واجهة (interface) على أساس كَوْنها -أي التوابع- عامة public ومُجردّة abstract. ولمّا كان هذا هو الخيار الوحيد المُتاح، فإن تَخْصِيص هذين المُبدِّلين (modifiers) ضِمْن التّصْريح (declaration) ليس ضروريًا. إلى جانب التّصريح (method declarations) عن التوابع، يُمكِن لأي واجهة (interface) أن تُصرِّح عن وجود مُتْغيِّرات (variable declarations)، وينبغي عندها أن تُصرِّح عنها على أساس كَوْنها عامة public، وساكنة static، ونهائية final، ولذا فإنها تَصيِر عامة وساكنة ونهائية بأي صنف يُنفِّذ (implements) تلك الواجهة. ولمّا كان هذا هو الخيار الوحيد المُتاح للتّصْريح عنها، فإن تَخْصِيص تلك المُبدِّلات (modifiers) ضِمْن التّصْريح (declaration) ليس ضروريًا. اُنظر المثال التالي: public interface ConversionFactors { int INCHES_PER_FOOT = 12; int FEET_PER_YARD = 3; int YARDS_PER_MILE = 1760; } هذه هي الطريقة المناسبة لتعريف (define) ثوابت مُسماة (named constants) يُمكِن اِستخدَامها بعدة أصناف. يُمكِن لأي صنف يُنفِّذ (implements) الواجهة ConversionFactors أن يَستخدِم الثوابت المُعرَّفة بتلك الواجهة (interface) كما لو كانت مُعرَّفة بالصنف. لاحِظ أن أي مُتْغيِّر مُعرَّف ضِمْن واجهة (interface) هو بالنهاية ثابت (constant) وليس مُتْغيِّرًا على الإطلاق. وفي العموم، لا يُمكِن لأي واجهة (interface) أن تُضيف مُتْغيِّرات نُسخ (instance variables) إلى الأصناف التي تُنفِّذها (implement). يُمكِن لأي واجهة (interface) أن تَتَمدَّد (extend) من واجهة واحدة أو أكثر. على سبيل المثال، إذا كان لدينا الواجهة Strokeable المُعطاة بالأعلى، بالإضافة إلى الواجهة Fillable والتي تُعرِّف التابع fill(g)‎، نستطيع عندها تعريف الواجهة التالية: public interface Drawable extends Strokeable, Fillable { // المزيد من التوابع أو الثوابت } ينبغي لأي صَنْف حقيقي (concrete class) يُنفِّذ الواجهة Drawable من أن يُوفِّر الأجزاء التّنْفيذية (implementations) لكُلًا من التابع stroke()‎ من الواجهة Strokeable، والتابع draw()‎ من الواجهة Fillable، بالإضافة إلى أي توابع مُجرّدة (abstract methods) آخرى قد تُخصِّصها الواجهة Drawable مباشرة. عادة ما تُعرَّف (define) الواجهة (interface) ضِمْن ملف ‎.java الخاص بها، والذي لابُدّ أن يَكُون له نفس اسم الواجهة. فمثلًا، تُعرَّف الواجهة Strokeable بملف اسمه Strokeable.java. وبالمثل من الأصناف (classes)، يُمكِن للواجهة (interface) أن تقع ضِمْن حزمة (package)، كما يُمكِنها أن تَستورِد (import) أشياءً من حزم آخرى. التوابع الافتراضية (default methods) بداية من الإصدار الثامن من الجافا، تستطيع الواجهات (interfaces) أن تَتَضمَّن ما يعرف باسم "التوابع الافتراضية (default methods)"، والتي تَملُك جزءًا تّنْفيذيًا (implementation) بعكس التوابع المُجرّدة (abstract methods) المُعتادة. تُورَث التوابع الافتراضية من الواجهات (interfaces) إلى أصنافها المُنفِّذة (implement) بنفس الطريقة التي تُورَث بها التوابع العادية من الأصناف إلى أصنافها الفرعية. لذا عندما يُنفِّذ (implement) صنف معين واجهةً تَحتوِي على توابع افتراضية، فإنه لا يَكُون مضطرًا لأن يُوفِّر جزءًا تّنْفيذيًا (implementation) لأي تابع افتراضي (default method) ضِمْن الواجهة، مع أن بإمكانه القيام بذلك إذا كان لديه تّنْفيذًا (implementation) مُختلفًا. تَدفَع التوابع الافتراضية (default methods) لغة الجافا خطوة للأمام بطريق دَعْم الوراثة المُتعدّدة (multiple inheritance)، ولكنها مع ذلك ليست وراثة مُتعدّدة بحق؛ لأن الواجهات لا تستطيع تعريف مُتْغيِّرات نُسخ (instance variables). تستطيع التوابع الافتراضية (default methods) استدعاء التوابع المجردة (abstract methods) المُعرَّفة بنفس الواجهة، لكنها لا تستطيع الإشارة إلى أي مُتْغيِّر نسخة (instance variable). ملحوظة: تستطيع واجهات نوع الدالة (functional interfaces) أيضًا أن تَحتوِي على توابع افتراضية (default methods) بالإضافة إلى التابع المُجرّد (abstract method) الوحيد الذي بإمكانها تَخْصِيصه. ينبغي أن تُصرِّح عن التوابع الافتراضية (default methods) على أساس كَوْنها عامة public، ولمّا كان ذلك هو الخيار الوحيد المُتاح، فإن تَخْصِيص المبدل public ضِمْن التّصْريح (declaration) ليس ضروريًا. في المقابل، لابُدّ من كتابة المُبدِّل default بشكل صريح أثناء التّصْريح عن أي تابع افتراضي (default method). اُنظر المثال التالي: public interface Readable { // تمثل مصدر إدخال public char readChar(); // اقرأ المحرف التالي المُدْخَل default public String readLine() { //اقرأ حتى نهاية السطر StringBuilder line = new StringBuilder(); char ch = readChar(); while (ch != '\n') { line.append(ch); ch = readChar(); } return line.toString(); } } لابُدّ لأي صنف حقيقي (concrete class) يُنفِّذ الواجهة (interface) -بالأعلى- من أن يُوفِّر تّنْفيذًا (implementation) للتابع readChar()‎. في المقابل، سيَرِث ذلك الصنف تعريف readLine()‎ من الواجهة، ولكنه قد يُوفِّر تعريفًا (definition) جديدًا إذا كان ذلك ضروريًا. عندما يَتَضمَّن صنف معين تّنفيذًا (implementation) لتابع افتراضي (default method)، فإن ذلك التّنْفيذ الجديد يُعيد تعريف (overrides) التابع الافتراضي الموجود بالواجهة (interface). بالمثال السابق، يَستدعِي التابع الافتراضي readLine()‎ التابع المُجرّد readChar()‎، والذي يَتوفَّر تعريفه (definition) فقط من خلال الأصناف المُنفِّذة للواجهة، ولهذا تُعدّ الإشارة إلى readChar()‎ مُتعدِّدة الأشكال (polymorphic). كُتب التّنْفيذ الافتراضي للتابع readLine()‎ بحيث يَكُون ملائمًا لأي صنف يُنفِّذ الواجهة Readable. اُنظر الشيفرة التالية والتي تَتَضمَّن صنفًا يُنفِّذ الواجهة Readable كما يَحتوِي على البرنامج main()‎ لاختبار الصَنْف: public class Stars implements Readable { public char readChar() { if (Math.random() > 0.02) return '*'; else return '\n'; } public static void main(String[] args) { Stars stars = new Stars(); for (int i = 0 ; i < 10; i++ ) { // اِستدعي التابع الافتراضي String line = stars.readLine(); System.out.println( line ); } } } تُوفِّر التوابع الافتراضية (default methods) إمكانية شبيهة لما يُعرَف باسم "المخلوط (mixin)" المُدعَّم ببعض اللغات البرمجية الآخرى، والتي تَعنِي المقدرة على خَلْط وظائف مصادر آخرى إلى داخل الصنف. لمّا كان بإمكان أي صنف أن يُنفِّذ أي عدد من الواجهات (interfaces)، فإنه يستطيع خلط وظائف عدة مصادر آخرى مختلفة. الواجهات كأنواع كما هو الحال مع الأصناف المُجرّدة (abstract classes)، لا يُمكِنك إنشاء كائن فعليّ من واجهة (interface)، ولكن تستطيع التّصْريح (declare) عن مُتْغيِّر نوعه عبارة عن واجهة. لنَفْترِض مثلًا أن لدينا الواجهة Strokeable المُعرَّفة بالأعلى، ويُنفِّذها كُلًا من الصنفين Line و Circle، يُمكِنك عندها كتابة التالي: // صرح عن متغير من النوع‫ Strokeable والذي يمكنه الإشارة إلى أي // كائن ينفذ تلك الواجهة Strokeable figure; figure = new Line(); // ‫يشير إلى كائن من الصنف Line figure.stroke(g); // ‫اِستدعي التابع stroke() من الصنف Line figure = new Circle(); // ‫يشير الآن إلى كائن من الصنف Circle figure.stroke(g); // ‫اِستدعي التابع stroke() من الصنف Circle يُمكِن لأي مُتْغيِّر من النوع Strokeable أن يُشير إلى أي كائن طالما كان صَنْفه يُنفِّذ الواجهة Strokeable. لمّا كان figure مُتْغيِّرًا من النوع Strokeable، ولأن أي كائن من النوع Strokeable يَحتوِي على التابع stroke()‎، فحتمًا سيَحتوِي الكائن الذي يُشير إليه المُتْغيِّر figure على التابع stroke()‎، ولهذا فإن التَعْليمَة figure.stroke(g)‎ صالحة تمامًا. تُستخدَم الأنواع (types) في العموم إما للتّصْريح (declare) عن مُتْغيِّر، أو لتَخْصِيص نوع معامل برنامج فرعي (routine)، أو لتَخْصِيص النوع المُعاد (return type) من دالة (function). النوع في العموم إما أن يَكُون صنفًا أو واجهة (interface) أو أحد الأنواع البسيطة (primitive) الثمانية المَبنية مُسْبَقًا (built-in). ليس هنالك من أيّ احتمال آخر، ربما باستثناء بعض الحالات الخاصة كأنواع التعداد (enum) والتي هي بمثابة نوع خاص من الأصناف. من بين كل تلك الأنواع، الأصناف هي الوحيدة التي يُمكِن اِستخدَامها لإنشاء كائنات (objects). يُمكِنك أيضًا اِستخدَام الواجهات (interface) لتَخْصِيص النوع الأساسي (base type) لمصفوفة. فمثلًا، تستطيع أن تُصرِّح عن مُتْغيِّر أو أن تُنشِئ مصفوفة باستخدام نوع المصفوفة Strokeable[]‎، وفي تلك الحالة، يُمكِن لعناصر تلك المصفوفة الإشارة إلى أي كائن طالما كان يُنفِّذ الواجهة Strokeable. اُنظر الشيفرة التالية: Strokeable[] listOfFigures; listOfFigures = new Strokeable[10]; listOfFigures[0] = new Line(); listOfFigures[1] = new Circle(); listOfFigures[2] = new Line(); . . . تَملُك جميع عناصر تلك المصفوفة التابع stroke()‎، مما يَعنِي إمكانية كتابة تعبيرات مثل listOfFigures.stroke(g)‎. ترجمة -بتصرّف- للقسم Section 7: Interfaces من فصل Chapter 5: Programming in the Large II: Objects and Classes من كتاب Introduction to Programming Using Java.
    1 نقطة
  4. السلام عليكم .. اريد انشاء مشروع بالنود جى اس وهو عبارة عن posts و users حيث ان كل يوزر يستطيع ان يقوم بعمل post وانشاءه والتعديل عليه ولكن لا يمكن لغيره ان يقوم بحدذفه او التعديل عليه .. انا اريد ان اقوم بانشاء هذا التطبيق باستخدام النود ولكن ليس عندى العلم الكافى ب jwt رجاء اريد docs او project على جيت هاب او حتى دورة توضيحية حتى يتسنى لى التعلم وشكرا
    1 نقطة
  5. ﻻ يمكنك إرسال الصورة في ملف جيسون حيث أن ملفات json يمكن أن تحتوي فقط على ملفات نصية (text) , ولكن يوجد حل بديل وهو أن تقوم بتشفير الصورة عبر base64 encoding وهو تشفير يقوم بتحويل الملفات الثنائية إلى حروف وأرقام ASCII تنفيذ الشفرة عبر node js const Base64 = Buffer.from(file).toString('base64'); نقوم بعد ذلك بتضمين ذلك النص في الرد الjson الذي نرسله إلى المُستحدم إستﻻم الصورة عبر الfront end من ناحية المُستخدم نقوم بوضع تشفير الbase64 الخاص بالصورة ولكن يسبقه data:image/png;base64, مثال على إستﻻم الصور عبر react <img src={`data:image/png;base64,${this.state.image}`}/>
    1 نقطة
  6. أريد طريقة لاستخدامها في اكتشاف الخطوط العمودية والأفقية، واعتقد أن HoughLines هو الطريقة الأفضل، لذا أريد مثال لتوضيح استخدامه؟
    1 نقطة
  7. السلام عليكم ورحمة الله وبركاتة فلنفترض لدينا قاعدة بيانات ( sql ) - ويوجد في القاعدة بعض الروابط ! مثال id - name - age - dmoin اريد طباعة الدومين لكن الشي الاخر يوجد مع الدومين نص مثال : ((((( رابط المتجر الخاص في محمد هو www.###.com ))))) يعني لو وضعتها في html بين كودين <a> راح يطلع مشكلة !! وأيضا تعديل في قاعدة البيانات صعب لكثرة الروابط ، هل يوجد هناك حل بسيط !؟
    1 نقطة
  8. يمكنك إستخدام دالة substring_index تلك الدالة تأخذل ثﻻث معاملات, الأول هو النص, الثاني هو العﻻمة الفاصلة, الثالث رقم تقوم الدالة بإرجاع النص من بعد العﻻمة الفاصلة أو من قبل العﻻمة الفاصلة على حسب إن كان الرقم في المعامل الثالث موجب أو سالب, إن كان موجب تقوم بإرجاع ماقبل العﻻمة, إن كان سالب تقوم بإرجاع ما بعد العﻻمة فيمكنك بالتالي تنفيذ الإستعﻻمة التالية select substring_index(domain,"http://","-1") from table_name; ومن ثم في وسم الhtml تقوم بوضعه ولكن نضع قبله كلمة http:// لأنها ستكون ممسوحة ونضع النص ككل بين وسم a بهذه الطريقة سيتم إرجاع الرابط فقط دون باقي الوصف وسيكون قابلاً للنقر أيضاً
    1 نقطة
  9. تقصد laravel/ui وليس bootstrap/ui , حزمة laravel/ui وهي مبنية باستخدام اطار عمل بوتستراب ,مدعومة الى حد الاصدار السابع من لارافيل وهي حزمة توفر نقطة انطلاق لأي تطبيق بسبب الميزات التي تتوفر في هذه الحزمة مثل نظام المصادقة كعمليات الدخول وغيرها , بينما في الاصدار الثامن من لارافيل تم التخلي عن بوتستراب واستخدام اطار العمل tailwind Css وهو اطار عمل مشابه لبوتستراب ولكن يحتوي على مميزات أكثر وبدأت كثير من التقنيات تدعمه لما يوفر من مميزات جيدة وأصناف كثيرة تسهل العمل , من ضمن التقنيات التي تدعم اطار العمل tailwind Css هي حزمة jetstream وهي حزمة توفر واجهات مصممة بشكل رائع وتوفر الكثير من المميزات الرائعة والتي يحتاجها أي موقع كنظام المصادقة والتحقق من البريد الإلكتروني والتوثيق الثنائي وإدارة الجلسة وواجهة برمجة التطبيقات عبر Laravel Sanctum وميزات إدارة الفريق الاختيارية , هذا هو الفرق بينهما , بالنسبة للشهادة , لا يكفي أن تتعلم فقط bootsrap/ui لأن الامتحان ربما سوف يكون في الاصدار الثامن والذي يستخدم حزمة jetstream , لذلك لا يكفي تعلم حزمة laravel/ui للحصول على الشهادة
    1 نقطة
  10. مرحبًا @واثق الشويطر نشكرك على الاهتمام بالمحتوى المنشور على الأكاديمية، كما نشكرك على الإشارة إلى المشكلة التي واجتهك. لقد صُحح الخلل الذي كان على مستوى الرابط، وبإمكانك الاطلاع الآن على محتوى المقال بنسخته الأصلية. أتمنى لك تجربة قراءة جيدة، والحصول على الفائدة المرجوة من المقال.
    1 نقطة
  11. الإصدار 1.0.0

    10334 تنزيل

    تُعد أنظمة التشغيل موضوعًا متقدمًا في العديد من برامج علوم الحاسوب، حيث يتعرف المتعلم على كيفية البرمجة بلغة C بحلول الوقت الذي يتعرف فيه على أنظمة التشغيل، وربما يأخذ المتعلم فصلًا دراسيًا في معمارية الحاسوب Computer Architecture قبل ذلك، فيصبح الهدف من تقديم هذا الموضوع عادةً هو عرض تصميم وتنفيذ أنظمة التشغيل للطلاب مع افتراض ضمني أن بعضهم سيجري بحثًا في هذا المجال، أو يكتب جزءًا من نظام تشغيل. هذا الكتاب مترجم عن الكتاب Think OS لكاتبه آلن داوني Allen B. Downey والذي يعد مسودة أولية لم تكتمل بصورة نهائية بعد إذ طُوّر لفصلٍ دراسي في كلية أولين Olin College يدعى أنظمة البرمجيات Software Systems. لا يفترض هذا الكتاب أنك قد درست معمارية الحاسوب، فيجب أن يمنحك فهمًا أفضل أثناء قراءته عن الحاسوب ومعماريته وكيف يعمل المعالج والذاكرة فيه وكيف تُدار العمليات وتُخزَّن الملفات وما يحدث عند تشغيل البرامج، وما يمكنك القيام به لجعل البرامج تعمل بصورة أفضل وأسرع بوصفك مبرمجًا. يشرح الفصل الأول بعض الاختلافات بين اللغات المُصرَّفة compiled واللغات المُفسَّرة interpreted، مع بعض الأفكار حول كيفية عمل المصرِّفات compilers، ويشرح الفصل الثاني كيف يستخدم نظام التشغيل العمليات لحماية البرامج قيد التشغيل من التداخل مع بعضها البعض. ويشرح الفصل الثالث الذاكرة الوهمية virtual memory وترجمة العناوين، ويتحدث الفصل الرابع عن أنظمة الملفات ومجرى البيانات، ويصف الفصل الخامس كيفية تشفير الأرقام والأحرف والقيم الأخرى، ويشرح أيضًا العامِلات الثنائية bitwise operators. أما الفصل السادس، فيشرح كيفية استخدام إدارة الذاكرة الديناميكية وكيفية عملها، ويدور الفصل السابع حول التخبئة caching وهرمية الذاكرة. ويشرح الفصل الثامن تعدد المهام multitasking والجدولة scheduling. ويدور الفصل التاسع حول خيوط POSIX وكائنات المزامنة mutexes، ويشرح الفصل العاشر المتغيرات الشرطية POSIX ومشكلة المنتج / المستهلك، ويدور الفصل الحادي عشر حول استخدام متغيرات تقييد الوصول POSIX وتطبيقها في لغة C. هذا الكتاب مرخص بموجب رخصة المشاع الإبداعي Creative Commons «نسب المُصنَّف - غير تجاري - الترخيص بالمثل 4.0». يمكنك قراءة فصول الكتاب على شكل مقالات من هذه الصفحة، «مدخل إلى أنظمة التشغيل»، أو تجدها مسردة بالترتيب التالي: الفصل الأول: مفهوم التصريف Compilation في لغات البرمجة الفصل الثاني: العمليات Processes في أنظمة التشغيل الفصل الثالث: الذاكرة الوهمية Virtual memory في نظام التشغيل الفصل الرابع: فهم الملفات Files وأنظمة الملفات file systems الفصل الخامس: تمثيل الأعداد والنصوص بالبتات وإجراء العمليات على مستوى البت الفصل السادس: إدارة الذاكرة Memory management في لغة C الفصل السابع: فهم عملية التخبئة Caching في معمارية الحاسوب الفصل الثامن: تعدد المهام Multitasking في الحواسيب الفصل التاسع: مفهوم الخيوط Threads في عملية المعالجة الفصل العاشر: المتغيرات الشرطية وحلها مشاكل التزامن بين العمليات في لغة C الفصل الحادي عشر: متغيرات تقييد الوصول Semaphores في لغة البرمجة سي C
    1 نقطة
  12. لا يمكن حساب تكلفة التطبيق بشكل صريح لأن التطبيقات تختلف في المواصفات والمميزات ولا توجد طريقة واضحة أو متبعة بشكل عام لحساب تكلفة أي مشروع، فالتكلفة تتبع نظام العرض والطلب ويمكن المساومة بين المبرمج والعميل على سعر المشروع والوقت المستغرق لإنشائه أيضًا وحتى التقنيات المستخدمه فيه، وأفضل طريقة لحساب متوسط تكلفة مشروع ميعن هي من خلال فحص سوق العمل والبحث عن مشاريع مشابهة تمت بالفعل، لمعرفة متوسط تكلفة المشروع، أما إن لم تتمكن من إيجاد مشروع مشابه فيمكنك أن تقوم بتحليل المشروع ومعرفة عدد الصفحات التقريبي فيه والأقسام في أغلب الصفحات وبالتالي سيمكنك أن تقوم بحساب تكلفة المشروع التقريبية وستستطيع تحديد الوقت الذي ستستغرقه في إنشاء هذا المشروع. يعتمد الأمر في البداية على العرض الذي تقدمه، ففي الغالب لا يكون العميل على دراية بالأمور التقنية مثل لغة البرمجة المستعملة في المشروع أو إطار العمل أو حتى قد لا يعرف الفرق بين واجهة المستخدم Frontend والواجهة الخلفية Backend، وبالتالي قد يكون طلب العميل هو إنشاء موقع كامل (Frontend & Backend)، ولكن طلبه لا يوضح هذا الأمر بشكل واضح، وذلك بسبب نقص الخبرة لدى العميل، وبالتالي يكون على المبرمج هنا أن يوضح هذا الأمر من بداية المشروع ويوضح للعميل ما سيحصل عليه بشكل كامل. أيضًا قد يكون لدى العميل تصور معين للمشروع النهائي، ولكن يمكن ان يحتوي تصوره هذا على مشاكل في بنية المشروع أو تجربة المستخدم أو حتى في تكلفة المشروع ككل، ويمكن للمبرمج في هذه الحالة أن يوضح للعميل أي الطرق أفضل بشكل بيسط لأداء مهمة معينة ولمذا يجب إستخدام تقنية معينة بدلًا من أخرى، فعلى سبيل المثال قد يرغب عميل ما إنشاء مدونة بلغة PHP ويمكن للمبرمج أن يقترح عليه أن يستخدم إطار عمل Laravel لإنشاء المشروع بشكل أسرع وأكثر آمانًا .. إلخ. وسيكون قرار العميل هو الفاصل في مثل هذه القرارات، فهذا مشروعه هو في النهاية. ولكي يكون العرض الذي تقدمه مناسبًا للعميل، فيجب فهم ما يريده العميل أولًا، ومحاولة عرض المميزات التي يقدمه المنتج الخاص بك مقارنة بما يريده العميل، فعلى سبيل المثال: إن كان العميل يريد إنشاء مدونة بإطار العمل Laravel، فيمكنك ان تقترح عليه المنتج الخاص بك الذي يوفر إنشاء التدوينات وتصنيفها في أقسام مع صفحة للبحث في المدونة وتحسين السيو الخاص بالموقع كذلك، بهذا الشكل يكون المنتج الخاص بك يغطي حاجة العميل، وكذلك يوفر له مميزات إضافية. قد تبدو المميزات السابقة بديهية وموجودة في أي مدونة، ولكن كما ذكرت سابقًا، فغالبًا لا يكون لدى العميل الفكرة الكاملة عن الأمور التقنية والمميزات التي يحتاجها بشكل كامل، لذلك يجب إستغلال هذا الأمر لعرض كل ما يقدمه منتجك. أما إن كان العكس، مثل أن يكون منتجك لا يحتوي على ميزة معينة يرغب به العميل، فيمكنك أن تعرض عليه إضافة هذه الميزة إلى منتجك وبيعه إياه -وسيكون هذا أفضل حل-، أو إستبدالها بميزة أخرى تغطي حاجته للميزة الأولى، مثل أن يرغب العميل بميزة إضافة وسوم إلى التدوينات، فتقترح عليه إستخدام الأصناف بدلًا منها مع توضيح سبب لذلك مثل أن الأصناف تكون أكثر تنظيمًا ويسهل على المستخدمين البحث فيها على سبيل المثال.
    1 نقطة
  13. في 2014 قامت شركة Xamarin بإنشاء نماذج Xamarin أو Xamarin.Forms والتي تُمكنك من إنشاء واجهة مستخدم User Interface ويتم تحويل الكود الخاص بها إلى تطبيق Android أو iOS أو Windows مباشرة، ستحتاج أن يكون لديك معرفة بلغة C# وكذلك أساسيات Xamarin نفسه وكيف يقوم بإنشاء التطبيقات على كل نظام تشغيل، وقد تم شرح هذا الأمر بشيء من التفصيل في المقالة التالية: أيضًا أنصحك أن تقرأ بعض من مقالات الأكاديمية حول Xamarin من هنا حيث يتم شرح كل الأساسيات بالإضافة إلى عدد من الأمور المتقدمة كذلك.
    1 نقطة
  14. تُعدّ الأصناف (classes) اللَبِنة الأساسية عالية المستوى (high-level) بالبرنامج، حيث تُستخدَم لتمثيل الأفكار والكيانات المُعقدة ضِمْن البرنامج وما يَرتبِط بها من بيانات (data) وسلوكيات (behavior). يَدفَع ذلك البعض إلى وَضْع الأصناف بمكانة خاصة، فيُحاولون تَجنُّب كتابة الأصناف الصغيرة جدًا والموجودة فقط لتجميع مجموعة من البيانات معًا، ويَرَونَها تافهة مع أنها قد تَكُون مفيدة أحيانًا أو حتى ضرورية في بعض الأحيان الآخرى. لحسن الحظ، تَرفَع الجافا هذا الحرج؛ حيث تَسمَح بكتابة تعريف صَنْف (class definition) ضِمْن تعريف صَنْف آخر، وبذلك لَمْ تَعُدْ تلك الأصناف الصغيرة جدًا موجودة بمُفردها، وإنما أَصبحَت جُزءًا من أصناف أكبر ذات هيبة. إلى جانب ذلك، هنالك العديد من الأسباب الآخرى التي قد تَدفَعك لتَضْمِين تعريف صنف (class definition) داخل صنف آخر. الصَنْف المُتداخِل (nested class) هو ببساطة أيّ صنف يَقَع تعريفه (definition) داخل تعريف صنف آخر. وفي الواقع، يُمكِن حتى كتابة تعريف صَنْف داخل تابع (method) والذي بدوره يَقَع ضِمْن صنف. الأصناف المُتداخِلة إِما أن تَكُون مُسمَاة (named) أو مجهولة الاسم (anonymous). سنعود لاحقًا إلى الأصناف مجهولة الاسم (anonymous classes) أما بالنسبة للأصناف المُتداخِلة المُسمَاة (named nested class)، فيُمكِنها أن تَكُون ساكنة (static) أو غَيْر ساكنة (non-static) وذلك كأي شيء مُعرَّف ضِمْن صَنْف. بالمثل من الأصناف، يُمكِن للواجهات (interfaces) أيضًا أن تَقَع ضِمْن تعريفات الأصناف (class definitions) وقد تَكُون ساكنة (static) أو غَيْر ساكنة (non-static)، كما قد تَحتوِي تعريفات الواجهات (interface definitions) على أصناف مُتداخِلة ساكنة (static nested classes) أو واجهات آخرى، ولكننا لن نَتَعرَّض لذلك. الأصناف المتداخلة (nested) الساكنة تُعرَّف الأصناف المُتداخِلة (nested class) الساكنة كأي تعريف لصَنْف عادي باستثناء أمرين: أولهما وقوع التعريف ضِمْن صنف آخر، والآخر اِستخدَام المُبدِّل static ضِمْن التّصْريح. يُعدّ أي صنف مُتداخِل ساكن جزءًا من البنية الساكنة (static) للصَنْف الحاضن له والذي قد يَستخدِمه لإنشاء كائنات بالطريقة العادية. في المقابل، يُمكِن اِستخدَامه أيضًا خارج صَنْفه الحاضن، ولكن ينبغي أن يُشير اسمه في تلك الحالة إلى كَوْنه عضوًا بصَنْفه الحاضن، أي ينبغي أن يُستخدَم الاسم الكامل للصنف والذي يَتَكوَّن من اسم صَنْفه الحاضن متبوعًا بنقطة ثم باسمه. كأيّ مُكوِّن ساكن آخر ضِمْن صَنْف، تُعدّ الأصناف المُتداخِلة (nested class) الساكنة جزءًا من الصَنْف ذاته بنفس الطريقة التي يُعدّ بها أي مُتْغيِّر عضو (member variable) ساكن جزءًا من الصَنْف ذاته. لنَفْترِض مثلًا وجود صَنْف، اسمه WireFrameModel يُمثِل مجموعة من الخطوط بفضاء ثلاثي الأبعاد. يَحتوِي ذلك الصنف على صَنْف مُتداخِل ساكن Line يُمثِل خطًا واحدًا. يُمكِننا الآن كتابة تعريف الصنف WireFrameModel والصنف المُتداخِل Line كالتالي: public class WireFrameModel { . . . // أعضاء آخرى ضمن الصنف static public class Line { // ‫يمثل خطًا من النقطة (x1,y1,z1) إلى النقطة (x2,y2,z2) بفضاء // ثلاثي الأبعاد double x1, y1, z1; double x2, y2, z2; } // ‫نهاية الصنف Line . . . // أعضاء آخرى ضمن الصنف } // ‫نهاية الصنف WireFrameModel لاحِظ أن الاسم الكامل للصَنْف المُتداخِل هو WireFrameModel.Line ويُمكِنك اِستخدَامه للتّصْريح عن مُتْغيِّر مثلًا. تستطيع تَحْديدًا إنشاء كائن من الصَنْف Line باِستخدَام البَانِي new Line()‎ من داخل الصَنْف WireFrameModel، بينما قد تَستخدِم التعبير new WireFrameModel.Line()‎ لإنشائه من خارج الصَنْف. يستطيع أي صَنْف مُتداخِل (nested) ساكن الوصول إلى أي عُضو ساكن (static members) مُعرَّف بالصنف الحاضن له حتى وإن كان عضوًا خاصًا (private). بالمثل، يستطيع الصَنْف الحاضن لصَنْف مُتداخِل (nested) ساكن الوصول إلى أعضاء ذلك الصنف المُتداخِل (nested) حتى وإن كانت خاصة (private). يُمثِل ذلك دافعًا قويًا لاِستخدَام الأصناف المُتداخِلة (nested)؛ نظرًا لأنها تَسمَح لصَنْف معين بالوصول إلى الأعضاء الخاصة (private) المُعرَّفة بصَنْف آخر دون الحاجة إلى إِتاحة تلك الأعضاء بصورة أعم لجميع الأصناف الآخرى. وأخيرًا، يُمكِن لأي صَنْف مُتداخِل (nested) أن يَكُون خاصًا (private) وعندها يُمكِن اِستخدَامه من داخل الصَنْف الحاضن له فقط. على الرغم من أن تعريف الصَنْف Line يَقَع ضِمْن الصَنْف WireFrameModel، ستُخزَّن النسخة المُصرَّفة (compiled) من الصَنْف Line بملف مُنفصل، اسمه هو WireFrameModel$Line.class، أي أنه عند تصريف تعريف الصَنْف (class definition) -بالأعلى-، سيُنشِئ المُصرِّف ملفًا منفصلًا لكل صَنْف. الأصناف الداخلية (inner) يُطلَق على الأصناف المُتداخِلة (nested) غَيْر الساكنة (non-static) اسم "الأصناف الداخلية (inner classes)". من الناحية العملية، هي لا تَختلِف كثيرًا عن الأصناف المُتداخِلة الساكنة (static)، مع أنها تُعدّ جزءًا من كائنات الأصَنْاف الحاضنة لها لا الأصناف ذاتها. لا تُعدّ الأعضاء غَيْر الساكنة (non-static) المُعرَّفة بأي صنف جزءًا فعليًا من الصنف ذاته على الرغم من أن شيفرتها مُتضمَّنة بتعريف ذلك الصنف (class definition)، وهو ما يَنطبِق على الأصناف الداخلية (inner classes). تُحدِّد تلك الأعضاء ما ستَحتوِيه كائنات ذلك الصنف عند إنشائها، وهو ما يَنطبِق أيضًا على الأصناف الداخلية على الأقل منطقيًا أي كما لو كان كل كائن من الصنف الحاضن يَتَضمَّن نسخة خاصة من الصَنْف المُتداخِل (nested) -لا تَأخُذ ذلك بالمعنى الحرفي-. بإمكان تلك النُسخة الوصول لجميع توابع النُسخ (instance methods) ومُتْغيَّرات النُسخ (instance variables) المُعرَّفة بالكائن حتى وإن كانت خاصة (private). مثلًا، إذا كان لدينا كائنين من صَنْف يَتَضمَّن صنفًا داخليًا (inner class)، فإن نُسختي الصَنْف الداخلي بهذين الكائنين مختلفتان؛ لأنهما يُشيران إلى مُتْغيَّرات نُسخ وتوابع نُسخ تَقَع ضِمْن كائنات مختلفة. كيف تُقرِّر ما إذا كان ينبغي لصنف مُتداخِل (nested) معين أن يَكُون ساكنًا أو غَيْر ساكن؟ الأمر بسيط للغاية: إذا اِستخدَم الصنف المُتداخِل مُتْغيِّر نسخة (instance variable) أو تابع نسخة (instance method) من الصَنْف الحاضن، فلابُدّ أن يَكُون غَيْر ساكن (non-static)، أما إن لم يَستخدِم أيًا منها، فيُمكِنه أن يَكُون ساكنًا (static). يُستخدَم الصنف الداخلي (inner class) في غالبية الأحوال ضِمْن الصَنْف الحاضن له فقط. وفي تلك الحالة، لا يَختلِف اِستخدَامه كثيرًا عن اِستخدَام أيّ صنف آخر؛ فيُمكِنك أن تُصرِّح عن مُتْغيِّر أو أن تُنشِئ كائنًًا باِستخدَام الاسم البسيط للصَنْف الداخلي، ولكن فقط ضِمْن الأجزاء غَيْر الساكنة (non-static) من الصَنْف. أما إذا أردت اِستخدَامه من خارج صَنْفه الحاضن له، فلابُدّ من الإشارة إليه باِستخدَام اسمه الكامل والذي يُكْتَب بالصياغة .، حيث أن هو مُتْغيِّر يُشير إلى كائن مُتضمِّن لصَنْف داخلي (inner class). لاحِظ أنه لكي تَتَمكَّن من إنشاء كائن ينتمي لصَنْف داخلي، لابُدّ أولًا أن تُنشِئ كائنًا من صَنْفه الحاضن. لنَفْترِض أننا نريد كتابة صنف يُمثِل مباراة بوكر، بحيث يَتَضمَّن صنفًا داخليًا يُمثِل لاعبي المباراة. يُمكِننا كتابة تعريف الصنف PokerGame كالتالي: public class PokerGame { // يمثل مباراة بوكر class Player { // يمثل أحد لاعبي المباراة . . . } // ‫نهاية الصنف Player private Deck deck; // مجموعة ورق اللعب private int pot; // قيمة الرهان . . . } // ‫نهاية الصنف PokerGame إذا كان game مُتْغيِّرًا من النوع PokerGame، فإنه سيَتَضمَّن نسخة خاصة به من الصَنْف Player على نحو منطقي. كأي صَنْف عادي آخر، تستطيع اِستخدَام التعبير new Player()‎ لإنشاء كائن جديد من الصَنْف Player بشَّرْط أن يَقَع ذلك داخل تابع نسخة (instance method) بكائن الصَنْف PokerGame. في المقابل، تستطيع اِستخدَام تعبير مثل game.new Player()‎ لإنشاء كائن من الصَنْف Player من خارج الصَنْف PokerGame، ولكنه في الواقع أمر نادر الحدوث. يستطيع أي كائن من الصَنْف Player الوصول إلى مُتْغيِّرات النُسخ deck و pot المُعرَّفة بكائن الصَنْف PokerGame. من الجهة الأخرى، يَمتلك أي كائن من الصَنْف PokerGame نسخة خاصة به من كُلًا من deck و pot و Players. فمثلًا، يَستخدِم لاعبو مباراة بوكر معينة المُتْغيِّرين deck و pot الخاصين بتلك المباراة تَحْديدًا، بينما يَستخدِم لاعبو مباراة بوكر آخرى المُتْغيِّرين deck و pot الخاصين بتلك المباراة الآخرى. ذلك بالتحديد هو تأثير كَوْن الصَنْف Player غير ساكن، وهو في الواقع الطريقة الطبيعية التي ينبغي للاعبين التصرُّف على أساسها. يُمثِل كل كائن من الصَنْف Player لاعبًا ضِمْن مباراة بوكر مُحدَّدة، أما إذا كان الصَنْف Player صَنْْفًا مُستقلًا أو صنفًا مُتداخِلًا (nested) ساكنًا، فسيُمثِل عندها الفكرة العامة للاعب البوكر بصورة مُستقلة عن أي مباراة بوكر مُحدَّدة. الأصناف الداخلية مجهولة الاسم (anonymous) قد تُعرِّف صنفًا داخليًا (inner class)، ثم تَجِد نفسك تَستخدِمه بسطر وحيد بالبرنامج، فهل ينبغي حقًا في تلك الحالة تعريف مثل ذلك الصنف؟ ربما، ولكن قد تُفضِّل أيضًا أن تَستخدِم صنفًا داخليًا مجهول الاسم (anonymous) في مثل هذه الحالات. يُكْتَب أي صَنْف داخلي مجهول الاسم بالصيغة التالية: new <superclass-or-interface> ( <parameter-list> ) { <methods-and-variables> } يُعرِّف الباني -بالأعلى- صَنْفًا جديدًا بدون أن يُعطيه أي اسم، ويُنشِئ كائنًا يَنتمِي إلى ذلك الَصَنْف عند تَشْغِيل البرنامج. في العموم، يُنشِئ هذا الشكل من العَامِل new -والذي تستطيع اِستخدَامه أينما استطعت اِستخدَام العامل new العادي- كائنًا جديدًا ينتمي لصَنْف مجهول الاسم يُشبه الصَنْف أو الواجهة ، والتي تَعمَل كأساس لصنف ذلك الكائن مع إضافة المُتْغيرِّات والتوابع المُعرَّفة، أي أنه يُنشِئ كائنًا فريدًا. الأهم من ذلك هو أنه يُنشئِه فقط بذلك الجزء من البرنامج حيث تحتاج إليه. لا يُشترَط أن يَكُون ذلك الأساس صنفًا، فيُمكِن أن يَكُون واجهة (interface) أيضًا، ولكن في تلك الحالة -أي اِستخدَام واجهة كأساس-، يَكُون الصَنْف مجهول الاسم مُلزَمًا بتّنْفيذ (implement) الواجهة، أي بتعريف (define) جميع التوابع المُصرَّح (declare) عنها ضِمْن تلك الواجهة كما أن قائمة المُعامِلات لابُدّ أن تَكُون فارغة. في المقابل، إذا اِستخدَمت صنفًا كأساس، فبإمكانك تمرير مُعامِلات (parameters) بحيث يَستقبِلها أحد البواني (constructor) المُعرَّفة بالصَنْف الأعلى . إذا كان لدينا الواجهة Drawable المُعرَّفة كالتالي: public interface Drawable { public void draw(GraphicsContext g); } لنَفْترِض الآن أننا نحتاج إلى كائن من النوع Drawable لكي يَرسِم مربعًا أحمر اللون طوله يُساوِي ١٠٠ بكسل. قد تختار أن تُعرِّف صنفًا جديدًا يُنفِّذ الواجهة Drawable، ثم تُنشِئ كائنًا منه. في المقابل، قد تَستخدِم صنفًا مجهول الاسم (anonymous class) لإنشاء الكائن بتَعْليمَة واحدة فقط، كالتالي: Drawable redSquare = new Drawable() { public void draw(GraphicsContext g) { g.setFill(Color.RED); g.fillRect(10,10,100,100); } }; يُشير redSquare -بالأعلى- إلى كائن يُنفِّذ الواجهة Drawable، ويَرسِم مربعًا أحمر اللون عند استدعاء تابعه draw()‎. لاحِظ أن الفاصلة المنقوطة بنهاية التَعْليمَة ليست جزءًا من تعريف الصنف (class definition)، وإنما هي تلك التي تُوجد بنهاية أي تَعْليمَة تّصْريح (declaration). يَشيع تمرير الأصناف مجهولة الاسم (anonymous class) كمُعامِلات فعليّة (actual parameters) للتوابع. فمثلًا، يَستقبِل التابع التالي كائنًا من النوع Drawable، ثم يَرسمه بسياقين رُسوميين (graphics contexts) مختلفين: void drawTwice( GraphicsContext g1, GraphicsContext g2, Drawable figure ) { figure.draw(g1); figure.draw(g2); } عندما تَستدعِي ذلك التابع، يُمكِنك أن تُمرِّر صنفًا داخليًا (inner class) مجهول الاسم (anonymous) كقيمة للمُعامِل (parameter) الثالث، كالتالي: drawTwice( firstG, secondG, new Drawable() { void draw(GraphicsContext g) { g.fillOval(10,10,100,100); } } ); يُنشِئ المُصرِّف ملف صنف ‎.class منفصل لكل صنف مُتداخِل (nested) مجهول الاسم ضِمْن الصَنْف. إذا كان اسم الصنف الأساسي هو MainClass، فإن أسماء ملفات الأصناف المتداخلة مجهولة الاسم تكون كالتالي: MainClass$1.class و MainClass$2.class و MainClass$3.class وهكذا. تُمثِل الواجهة Drawable المُعرَّفة بالأعلى واجهة نوع دالة (functional interface)، وبالتالي نستطيع في هذه الحالة اِستخدَام تعبيرات لامدا (lambda expressions) بدلًا من الأصناف مجهولة الاسم. يُمكِن إعادة كتابة المثال الأخير كالتالي: drawTwice( firstG, secondG, g -> g.fillOval(10,10,100,100) ); كما يُمكِن إعادة تعريف المُتْغيِّر redSquare كالتالي: Drawable redSquare = g -> { g.setFill(Color.RED); g.fillRect(10,10,100,100); }; لا يُنشِئ المُصرِّف أي ملفات جديدة لتعبيرات لامدا (lambda expressions) وهو ما يُحسَب لها، ولكن لاحِظ أنها تُستخدَم فقط مع واجهات نوع الدالة (functional interfaces). في المقابل، تستطيع اِستخدَام الأصناف مجهولة الاسم (anonymous classes) مع أي واجهة أو صنف. قبل الإصدار ٨ من الجافا، كانت الأصناف مجهولة الاسم تُستخدَم لمعالجة الأحداث (events) ببرامج واجهات المُستخدِم الرُسومية (GUI)، ولكن مع الإصدار ٨ ومنصة جافا إف إكس (JavaFX)، أصبحت تعبيرات لامدا مُستخدَمة بكثرة ضِمْن هذا السياق بدلًا من الأصناف مجهولة الاسم. الأصناف المحلية (local) وتعبيرات لامدا تستطيع أن تُعرِّف صنفًا ضِمْن تعريف برنامج فرعي (subroutine definition). تُعرَف تلك النوعية من الأصناف باسم "الأصناف المحلية (local classes)". يَقْتصِر اِستخدَام أي صنف محلي على البرنامج الفرعي (subroutine) المُعرَّف بداخله، ولكن يُمكِن لكائنات ذلك الصنف أن تُستخدَم خارج البرنامج الفرعي، فمثلًا، قد يُعاد كائن ينتمي لصنف محلي من برنامج فرعي أو قد يُمرَّر كمُعامِل (parameter) لبرنامج فرعي آخر. هذا ممكن لأننا نستطيع عمومًا إِسْناد كائن ينتمي لصنف معين B إلى مُتْغيِّر من النوع A طالما كان B صنفًا فرعيًا من A في حالة كان A عبارة عن صنف، أما إذا كان واجهة فطالما كان B يُنفِّذ A. لنَفْترِض مثلًا أن لدينا برنامج فرعي (subroutine) يَستقبِل مُعامِلًا من النوع Drawable -الواجهة المُعرَّفة بالأعلى-، فنستطيع ببساطة أن نُمرِّر إليه أي كائن طالما كان يُنفِّذ (implements) تلك الواجهة، وعليه، قد ينتمي الكائن لصنف محلي (local class) يُنفِّذ تلك الواجهة. بمثال سابق بهذا القسم، مَرَّرنا كائنًا من النوع Drawable إلى التابع drawTwice()‎، والذي يَستقبِل مُعاملًا (parameter) من النوع Drawable. في ذلك المثال، كان الصنف المُمرَّر صنفًا داخليًا مجهول الاسم (anonymous inner class). لاحِظ أن الأصناف المحلية عادة ما تَكُون مجهولة الاسم (anonymous) والعكس، لكنه مع ذلك ليس أمرًا ضروريًا. فمثلًا، قد تَستخدِم صنفًا مجهول الاسم لتعريف القيمة المبدئية لمُتْغيِّر عام (global variable). في تلك الحالة، لا يَقع الصَنْف ضِمْن أي برنامج فرعي (subroutine)، وبالتالي لا يُعدّ محليًا (local). يُمكِن لأي صَنْف محلي (local class) أن يُشير إلى أي مُتْغيِّر محلي (local variables) ضِمْن برنامجه الفرعي أو إلى أي من مُعامِلاته (parameters) المُمرَّرة، ولكن وفقًا لعدة شروط: لابُدّ أن يُصرَّح عن ذلك المُتْغيِّر المحلي (local variable) أو المُعامِل (parameter) باستخدام المُبدِّل final أو أن يَكُون على الأقل "نهائيًا على نحو فعال". يُعدّ المُعامِل (parameter) "نهائيًا على نحو فعال" إذا لم تَتغيّر قيمته داخل البرنامج الفرعي (subroutine) بما في ذلك أصنافه المحلية (local class) التي أشارت إلى ذلك المُعامِل (parameter) بينما يُعدّ المُتْغيِّر المحلي (local variable) "نهائيًا على نحو فعال" إذا لم تَتغيّر قيمته أبدًا بعد التهيئة المبدئية (initialize). في المقابل، تستطيع الأصناف المحلية الإشارة إلى أي مُتْغيِّر عام (global variables) ودون أي شروط. تَنطبِق نفس شروط اِستخدَام المُتْغيِّرات المحلية (local variables) على تعبيرات لامدا (lambda expressions)، والتي هي كثيرة الشبه بالأصناف مجهولة الاسم (anonymous classes). تَستعرِض الشيفرة التالية برنامجًا فرعيًا يَستخدِم كُلًا من واجهة برمجة التطبيقات stream والواجهة Runnable -ناقشناها بالقسم ٤.٥-؛ لطباعة الأعداد من ١ إلى ١٠ بترتيب غير مُحدَّد يَعتمِد على مجرى مُتوازي (parallel stream): static void print1to10() { ArrayList<Runnable> printers = new ArrayList<>(); for (int i = 1; i <= 10; i++) { int x = i; printers.add( () -> System.out.println(x) ); } printers.parallelStream().forEach( r -> r.run() ); } لمّا كان المُتْغيِّر المحلي x "نهائيًا على نحو فعال"، تَمكَّنا من اِستخدَامه ضِمْن تعبير لامدا (lambda expression). في المقابل، لا يُمكِن اِستخدَام المُتْغيِّر i ضِمْن تعبير لامدا؛ لأنه غَيْر نهائي حيث تَتغيّر قيمته عند تّنْفيذ التعبير i++‎. ترجمة -بتصرّف- للقسم Section 8: Nested Classes من فصل Chapter 5: Programming in the Large II: Objects and Classes من كتاب Introduction to Programming Using Java.
    1 نقطة
  15. يمكنك تحديد رسائل معينة لكي تظهر عند حدوث خطأ في صحة البيانات من خلال إضافة مصفوفة أخرى إلى التابع validate كالتالي: $validationRules = [ 'name' => 'required', 'email' => 'required|email', 'message' => 'required|max:250', ]; $this->validate( $request, [ 'name' => 'required', 'email' => 'required|email', 'message' => 'required|max:250', ], [ 'required' => 'هذا الحق مطلوب', 'email' => 'يجب أن يكون هذا الحقل عبارة عن بريد إلكتروني' ] ); يمكن أيضًا تخزين كل من الرسائل الخاصة وقواعد التحقق من صحة البيانات في متغيرين لجعل الكود أكثر قابلية للقراءة.
    1 نقطة
  16. أغلب المواقع والتطبيقات تستخدم نفس الطريقة تقريبًا وهي تحديد يوم معين (أول يوم في رمضان) وحساب الوقت المتبقي حتى حلول هذا اليوم، يمكنك فعل نفس الشيء من خلال إضافة jQuery.countdown، فعلى سبيل المثال الكود التالي يقوم بحساب الوقت المتبقي على بداية شهر رمضان (بفرض أن رمضان سيبدأ في يوم 13 أبريل في الساعة 19:00) ويظهر هذا الوقت المتبقي في العنصر #getting-started: <div id="getting-started"></div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="https://raw.githubusercontent.com/hilios/jQuery.countdown/master/dist/jquery.countdown.min.js"></script> <script type="text/javascript"> $('#getting-started').countdown('2021/04/13 19:00:00', function(event) { $(this).html(event.strftime('متبقي %D يومًا و %H:%M:%S')); }); </script> كما يوجد عشرات المكتبات والإضافات التي تقوم بمثل هذا الأمر، ويمكن الوصول إلى هذه المكتبات من خلال بحث بسيط في GitHub.
    1 نقطة
  17. تُعدّ الأفكار الأساسية التي تَرتَكِز عليها البرمجة كائنية التوجه (object-oriented programming) واضحة وبسيطة على نحو معقول، ومع ذلك فإنها ستَأخُذ منك بعض الوقت لكي تَعتَاد عليها تمامًا. بالإضافة إلى ذلك، هنالك الكثير من التفاصيل الدقيقة وراء تلك الأفكار الأساسية والتي قد تَكُون مزعجة في بعض الأحيان. سنُحاوِل أن نُغطِي بعضًا منها بالجزء المُتبقِي من هذا الفصل، وتَذَكَّر أنه ليس ضروريًا أن تَتَمكَّن من إِتقان كل تلك التفاصيل خاصة عند قرائتها لأول مرة. سنَفْحَص بهذا القسم تحديدًا المُتْغيِّرين this و super المُعرَّفين تلقائيًا بأي تابع نسخة (instance method) أو بَانِي كائن (constructor). المتغير الخاص this ما الذي يعنيه اِستخدَام مُعرِّف بسيط مثل amount أو process()‎ للإشارة إلى مُتْغيِّر أو تابع؟ تعتمد الإجابة بشكل أساسي على قواعد النطاق (scope rules)، والتي تُوضِح الأماكن التي يُمكِنها الوصول إلى أيّ مُتْغيِّر أو تابع قد صَرَّح عنه البرنامج وكيفية القيام بذلك. فمثلًا، قد يُشير اسم بسيط لمُتْغيِّر بتعريف تابع (method definition) إلى مُتْغيِّر محليّ (local variable) أو مُعامِل (parameter) في حالة وجود أي منهما ضِمْن النطاق (scope)، أيّ إن كان التَّصْريح (declaration) عن أيّ منهما ما يزال فعالًا بمكان حُدوث تلك الإشارة بالشيفرة، فإذا لم يَكُن كذلك، فإن ذلك الاسم لابُدّ وأنه يُشير إلى مُتْغيِّر عضو (member variable) مُعرَّف بنفس الصنف الذي حدثت فيه تلك الإشارة. بالمثل، أي اسم بسيط لتابع لابُدّ وأنه يُشير إلى تابع (method) مُعرَّف بنفس الصنف. يَملُك أي عضو ساكن (static member) بصنف اسمًا بسيطًا يُمكِن اِستخدَامه داخل تعريف الصَنْف (class definition) فقط. في المقابل، يُستخدَم الاسم الكامل للعضو . للإشارة إليه من خارج الصَنْف. فمثلًا، Math.PI هو مُتْغيِّر عضو ساكن (static member variable) اسمه البسيط هو PI داخل الصنف Math. لاحِظ أنه من المُمكن دومًا الإشارة إلى أي عضو ساكن باِستخدَام اسمه الكامل حتى من داخل الصنف المُعرَّف بداخله بل قد يَكُون ذلك ضروريًا في بعض الأحيان، مثلًا عندما يَكُون الاسم البسيط للمُتغير الساكن مخفيًا نتيجة وجود مُتْغيِّر محليّ (local variable) أو مُعامِل (parameter) بنفس الاسم. بالمثل، يَملُك أي عضو نسخة (instance member)، سواء كان مُتْغيِّر نسخة (instance variable) أو تابع نسخة (instance method)، اسمًا بسيطًا يُمكِن اِستخدَامه بتوابع النسخ (instance methods) -لا التوابع الساكنة (static methods)- بالصنف المُعرَّف بداخله. تَذَكَر أن أي مُتْغيِّر نسخة أو تابع نسخة هو جزء من الكائن ذاته وليس صَنْفه، فكل كائن يَمتلك نسخة خاصة به من ذلك المُتْغيِّر أو التابع. بالإضافة إلى الاسم البسيط، يَملُك أي عضو نسخة (instance member) اسمًا كاملًا، شطره الأول عبارة عن مَرجِع (reference) يُشير إلى الكائن المُتضمِّن لذاك العضو. مثلًا، إذا كان std مُتْغيِّر يُشير إلى كائن من النوع Student، فقد تُمثِل std.test1 الاسم الكامل لمُتْغيِّر نسخة (instance variable) اسمه test1 مُعرَّف ضِمْن الكائن. إذًا، عندما تَستخدِم الاسم البسيط لمُتْغيِّر نُسخة (instance variable) مثل test1 بداخل صنف معين، أين الكائن الذي يَتَضمَّن ذلك المُتْغيِّر؟ في الواقع، الأمر بسيط نوعًا ما. لنَفْترِض أنك أَشرت إلى الاسم test1 بتعريف تابع نسخة (instance method) معين، والذي هو بالتأكيد جزء من كائن من النوع Student. عندما يُنفَّذ ذلك التابع، فإن الاسم البسيط test1 يُشير عندها إلى المُتْغيِّر test1 المُعرَّف بذلك الكائن. في الواقع، هذا هو السبب وراء عدم إمكانية استخدام الأسماء البسيطة لأعضاء النسخ (instance members) ضِمْن أي تابع ساكن (static methods)؛ لأنه وبينما يُنفَّذ ذلك التابع الساكن، لا يَكُون هناك أي كائن، ومن ثم لا يَكُون هناك أي أعضاء نُسخ (instance members). يَضَعنا هذا أمام السؤال التالي: كيف نَستخدِم الاسم الكامل لعضو نسخة (instance members) داخل نفس الصَنْف المُعرَّف بداخله؟ نُريد ببساطة طريقة تُمكِّنا من الإشارة إلى "نفس ذات الكائن الحاضن للتابع". في الواقع، تُوفِّر الجافا المُتْغيِّر الخاص this لهذا الغرض. تستطيع اِستخدَام المُتْغيِّر this بتابع نسخة معين (instance method)؛ للإشارة إلى نفس ذات الكائن الحاضن لنفس ذات التابع. فمثلًا، إذا كان var هو مُتْغيِّر نسخة (instance variable) مُعرَّف بنفس ذات الكائن الحاضن لنفس ذات التابع، فإن this.var هو الاسم الكامل لذلك المُتْغيِّر. وبالمثل، إذا كان otherMethod()‎ هو تابع نسخة (instance method) بنفس ذات الكائن، فيُمكِن اِستخدَام this.otherMethod()‎ لاستدعاء ذلك التابع. عندما يُنفِّذ الحاسوب تابع نسخة (instance method) معين، فإنه تلقائيًا يَضَع المُتْغيِّر this بحيث يُشير إلى نفس ذات الكائن الحاضن للتابع. تَستخدِم بعض اللغات البرمجية كائنية التوجه (object oriented) الاسم self بدلًا من this. يُرَى عندها الكائن ككيان يَستقبِل الرسائل، ويَرُد عليها بتَّنْفيذ أمر معين. وفقًا لذلك الكيان، يُشير مُتْغيِّر نسخة (instance variable) مثل self.name إلى نسخة name الخاصة بالكيان، بينما يَكُون استدعاء تابع نسخة (instance method) مثل self.redraw()‎ بمثابة قوله "اِرسِل إلى نفسي رسالة redraw". يَشيع استخدام المُتْغيِّر الخاص this ببواني الكائنات (constructors)، كالتالي: public class Student { private String name; // اسم الطالب public Student(String name) { this.name = name; } . . // المزيد من المتغيرات والتوابع . } بباني الكائن (constructor) -بالأعلى-، أَصبَح مُتْغيِّر النسخة (instance variable)‏ name مَخفيًّا نتيجة اِستخدَام مُعامِل صُّوريّ (formal parameter) يَحمِل نفس الاسم name. مع ذلك، تستطيع اِستخدَام اسمه الكامل this.name للإشارة إليه. يُشير الاسم name على يمين تَعْليمَة الإِسْناد this.name = name إلى المُعامِل الصُّوريّ (formal parameter)، وتُسنَد قيمته إلى مُتْغيِّر النسخة this.name. يَشيِع اِستخدَام تلك الصياغة، وهي مقبولة في العموم؛ فليس هناك أي حاجة لاختيار أسماء جديدة للمُعامِلات الصُّوريّة المُستخدَمة فقط لتهيئة مُتْغيِّرات النُسخ (instance variables)، لذا اِستخدِم نفس الاسم لكليهما ببساطة. يُستخدَم المُتْغيِّر الخاص this لأغراض آخرى أيضًا. على سبيل المثال، بينما تَكْتُب تابع نسخة (instance method)، قد تحتاج إلى تمرير الكائن الحاضن للتابع إلى برنامج فرعي (subroutine) كمُعامِل فعليّ (actual parameter). في تلك الحالة، تستطيع ببساطة تمرير this. مثلًا، يُستخدَم System.out.println(this);‎ لطباعة تمثيل نصي (string representation) للكائن. بالإضافة إلى ذلك، قد تُسنِد this إلى مُتْغيِّر آخر ضِمْن تَعْليمَة إِسْناد (assignment statement) أو تُخزِّنه بمصفوفة. وفي العموم، تستطيع أن تَفعَل به أي شيء يُمكِنك فعله مع أي مُتْغيِّر آخر باستثناء تَعْدِيل قيمته (اِفْترِض أنه مُتْغيِّر نهائي مُعرَّف باِستخدَام المُبدِّل final). المتغير الخاص super تُعرِّف الجافا المُتْغيِّر الخاص super للاِستخدَام بتعريفات توابع النُسخ (instance methods) بالأصناف الفرعية (subclasses) تحديدًا. بالمثل من this، يُشير المُتْغيِّر الخاص super إلى نفس ذات الكائن الحاضن للتابع، ولكنه يَنسَى -إذا جاز التعبير- أن ذلك الكائن ينتمي إلى صَنْفه الفرعي (subclass)، ويَتَذكَّر فقط انتماءه إلى صَنْفه الأعلى (superclass). الفكرة ببساطة كالتالي: قد يَتَضمَّن الصَنْف الفرعي بعض الإضافات إلى الصَنْف الأعلى (superclass) أو حتى بعض التَعْديلات عليه، فكانت الحاجة إلى وجود طريقة للإشارة إلى التوابع (methods) والمُتْغيِّرات المُعرَّفة بالصَنْف الأعلى (superclass)، وهذا ما يُوفِّره المُتْغيِّر super فهو ببساطة لا يَعلَم أي شيء عن تلك الإضافات والتعديلات. لنَفْترِض أن لديك صَنْف فرعي يَحتوِي على تابع نسخة (instance method) اسمه doSomething()‎، ثُمَّ كَتبَت بأحد توابعه تَعْليمَة استدعاء البرنامج الفرعي التالية super.doSomething()‎. لمّا كان المُتْغيِّر super لا يَعلَم أي شيء عن التابع doSomething()‎ المُعرَّف بالصنف الفرعي، فهو فقط يَعلَم الأشياء المُعرَّفة بالصنف الأعلى (superclass)، فإنه سيُحاوِل تَّنْفيذ تابع اسمه doSomething()‎ من الصَنْف الأعلى (superclass)، فإذا لم يَجِدْه، أيّ في حالة كان التابع doSomething()‎ إضافةً وليس تعديلًا، فستَحصُل على خطأ في بناء الجملة (syntax error). وفَّرت الجافا المُتْغيِّر الخاص super لكي تَتَمكَّن من الوصول إلى أشياء كانت قد عُرِّفت بالصنف الأعلى (superclass)، ولكنها أصبحت مَخفيّة بواسطة بعض الأشياء المُعرَّفة بالأصناف الفرعية (subclasses). مثلًا، دائمًا ما سيُشير الاسم super.var إلى مُتْغيِّر النسخة (instance variable)‏ var المُعرَّف بالصنف الأعلى (superclass). يَكُون ذلك مفيدًا في بعض الحالات كالتالي: إذا اِحتوَى صنف معين على مُتْغيِّر نسخة (instance variable) له نفس اسم مُتْغيِّر نسخة بصنفه الأعلى (superclass)، فعندها سيَحتوِي أي كائن من الصَنْف الفرعي على مُتْغيِّرين لهما نفس الاسم، الأول مُعرَّف كجزء من الصنف نفسه، والآخر مُعرَّف كجزء من الصنف الأعلى، أيّ لا يَحلّ المُتْغيِّر بالصنف الفرعي (subclass) مَحلّ المُتْغيِّر بالصَنْف الأعلى حتى لو كان لهما نفس الاسم وإنما يُخفيه فقط، وعليه ما يزال المُتْغيِّر من الصنف الأعلى قابلًا للوصول باِستخدَام super. بالمثل، عندما يَتَضمَّن صنف فرعي (subclass) تابع نسخة (instance method) له نفس بصمة (signature) تابع مُعرَّف بالصنف الأعلى (superclass)، فإن التابع من الصنف الأعلى يُصبِح مَخفيًّا بنفس الطريقة، ويُقال عندها أن التابع من الصنف الفرعي أعاد تعريف (override) التابع من الصنف الأعلى. ومع ذلك، يُمكِن اِستخدَام المُتْغيِّر الخاص super للوصول إلى التابع من الصنف الأعلى (superclass). غالبًا ما يُستخدَم المُتْغيِّر super لتمديد (extend) سلوك تابع موروث بدلًا من أن يستبدله بالكامل، وذلك بكتابة تابع جديد يُعيد تعريف (override) التابع الأصلي. يَتَضمَّن التابع الجديد استدعاءً لتابع الصنف الأعلى (superclass) من خلال المُتْغيِّر super إلى جانب الشيفرة الجديدة المطلوب إضافتها بالأساس. لنَفْترِض مثلًا أن لدينا الصنف PairOfDice والذي يَتَضمَّن تابعًا اسمه roll()‎، والآن نريد إنشاء صنف فرعي GraphicalDice ليُمثِل حجري نَّرد مرسومين على الشاشة. ينبغي للتابع roll()‎ المُعرَّف بالصنف الفرعي GraphicalDice أن يُنفِّذ كل شيء يقوم به التابع roll()‎ المُعرَّف بالصنف الأعلى PairOfDice، وهو ما يُمكِننا التعبير عنه بالاستدعاء super.roll()‎، والذي سيَستدعِي نسخة التابع بالصنف الأعلى (superclass). بالإضافة إلى ذلك، ينبغي للتابع roll()‎ المُعرَّف بالصنف الفرعي GraphicalDice أن يُعيد رسم حجرى النَّرد لإظهار القيم الجديدة. يُمكِننا تعريف الصنف GraphicalDice كالتالي: public class GraphicalDice extends PairOfDice { public void roll() { super.roll(); // ‫استدعي roll من الصنف PairOfDice redraw(); // استدعي تابع لرسم حجري النرد } . . // ‫المزيد بما يتضمن تعريف redraw() . } يَسمَح ذلك عمومًا بتمديد (extend) سلوك التابع roll()‎ حتى لو لم تَكُن على علم بطريقة تَّنْفيذه (implementation) بالصنف الأعلى. super و this كبواني كائن لا تُورَث بواني الكائن (constructors) عمومًا، أي أنك إذا أنشأت صنفًا فرعيًا (subclass) من صنف موجود، فإن بواني الكائن المُعرَّفة بالصنف الأعلى (superclass) لا تُصبِح جزءًا من الصنف الفرعي. يُمكِنك إضافة بواني جديدة بالصنف الفرعي إذا أردت، وفي حالة عدم إضافتها، سيُنشِئ الحاسوب بَانِي كائن افتراضي (default constructor) بدون أي مُعامِلات (parameters). إذا كان الصنف الأعلى (superclass) يَحتوِي على باني كائن (constructor) يُنفِّذ الكثير من التهيئة الضرورية، فيبدو أنك ستَضطرّ إلى تَكْرار كل ذلك العمل بالصنف الفرعي. بالإضافة إلى ذلك، قد لا تَملُك شيفرة الصنف الأعلى (superclass)، ولا تَعلَم حتى طريقة تَّنْفيذها (implementation)، وهو ما قد يُمثِل مشكلة حقيقية، والتي قد تُصبِح مستحيلة إذا كان الباني المُعرَّف بالصنف الأعلى يَستخدِم مُتْغيِّرات أعضاء خاصة (private member variables)، ففي تلك الحالة، أنت لا تَملُك حتى صلاحية للوصول إليها من الصنف الفرعي. لابُدّ إذًا من وجود طريقة لإصلاح ذلك. في الواقع، قد يُستخدَم المُتْغيِّر الخاص super كأول تَعْليمَة بالباني (constructor) المُعرَّف بالصنف الفرعي؛ لكي يَستدعِي الباني (constructor) المُعرَّف بالصنف الأعلى (superclass). قد تَكُون طريقة كتابة ذلك مُضللة نوعًا ما؛ فهي تبدو كما لو كنت تَستدعِي super كبرنامج فرعي (subroutine) على الرغم من أنه ليس كذلك، وفي العموم لا يُمكِنك استدعاء البواني (constructors) بنفس طريقة استدعاء البرامج الفرعية. والآن، لنَفْترِض أن الصنف PairOfDice يَتَضمَّن باني كائن (constructor) يَستقبِل مُعامِلين (parameters) من النوع int، يُمكِننا إذًا أن نُعرِّف صنفًا فرعيًا (subclass) منه كالتالي: public class GraphicalDice extends PairOfDice { public GraphicalDice() { // باني كائن لهذا الصنف // استدعي الباني من الصنف الأساسي بقيم المعاملات 3 و 4 super(3,4); initializeGraphics(); // نفذ التهيئة الخاصة بالصنف الفرعي } . . // المزيد من البواني والمتغيرات والتوابع . } تَستدعِي التَعْليمَة super(3,4);‎ الباني (constructor) المُعرَّف بالصنف الأعلى. لابُدّ من كتابته بالسطر الأول من الباني المُعرَّف بالصنف الفرعي (subclass)، وفي حالة عدم استدعاء أي باني من الصنف الأعلى بصورة صريحة، يُستدعَى تلقائيًا بَانِي الصنف الأعلى الافتراضي (default constructor) أي ذلك الذي لا يَستقبِل أي مُعامِلات (parameters)، وإذا لم يَكُن موجودًا، سيُبلِّغ المُصرِّف (compiler) عن وجود خطأ في بناء الجملة (syntax error). يُستخدَم المُتْغيِّر الخاص this بنفس الطريقة تمامًا، ولكن لاستدعاء باني (constructor) آخر ضِمْن نفس الصنف. سيَبدُو عندها السطر الأول من الباني كما لو كان استدعاءً لبرنامج فرعي اسمه هو this، وسيُنفَّذ عندها مَتْن الباني المُستدعَى مما يُجنّبك تكرار نفس الشيفرة ضِمْن عدة بواني مختلفة. على سبيل المثال، يُستخدَم الصنف MosaicCanvas -من القسم ٤.٧- لتمثيل شبكة من المستطيلات الملونة، ويَتَضمَّن باني يَستقبِل أربعة مُعامِلات (parameters) كالتالي: public MosaicCanvas(int rows, int columns, int preferredBlockWidth, int preferredBlockHeight) يَستقبِل ذلك الباني مجموعة من الخيارات يُنفِّذ على أساسها الكثير من التهيئة (initialization). قد تحتاج إلى إضافة بواني (constructors) آخرى بعدد أقل من الخيارات لتَكُون أسهل في الاِستخدَام، ولكن ما يزال تَّنْفيذ التهيئة كاملة أمرًا ضروريًا. يَحتوِي الصنف على البواني التالية: public MosaicCanvas() { this(42,42); } public MosaicCanvas(int rows, int columns) { this(rows,columns,16,16); } يَستدعِى كل باني كائن (constructor) منهما باني كائن آخر بالإضافة إلى توفير قيم ثابتة للمُعامِلات الآخرى التي لم يَستقبِلها. على سبيل المثال، يَستدعِي التعبير this(42,42)‎ الباني الثاني، والذي بدوره يَستدعِي الباني الأساسي ذو المُعامِلات الأربعة. في الواقع، يُستدعَى الباني الأساسي بجميع الحالات وذلك لضمان تَّنْفيذ التهيئة (initialization) الضرورية كاملةً. ترجمة -بتصرّف- للقسم Section 6: this and super من فصل Chapter 5: Programming in the Large II: Objects and Classes من كتاب Introduction to Programming Using Java.
    1 نقطة
×
×
  • أضف...