البحث في الموقع
المحتوى عن 'oriented object'.
-
تعرّفنا فيما سبق من دروس هذه السلسلة على أساسيات لغة بايثون، من مُتغيّرات وحلقات تكرار إلى الدوال، وقد حان الوقتُ للدخول إلى أساسيات البرمجة كائنية التوجّه Object Oriented Programming وهي ببساطة طريقة أخرى للبرمجة بحيث تكون أجزاء الشّيفرة مجموعة داخل دوال تُسمّى التوابع methods والدوال تكون داخل صنف معيّن Class. عند إنشاء كائن object من هذا الصنف فإنّنا نستطيع أن نُنفّذ عليه مُختلف العمليات الموجودة داخل التوابع والتي بدورها توجد داخل الصنف. هناك تسميّات عربية أخرى لهذا النّوع من البرمجة، لذا لا تقلق إذا صادَفتَ أحد هذه التّسميات في أماكن أخرى، فكلّها تُشير إلى نفس المعنى: برمجة غرضيّة التوجه برمجة شيئية المنحى برمجة كائنيّة المنحى بنية الصنف Class الصنف ببساطة يحتوي على أجزاء مُختلفة من الشيفرة تماما مثل الدالة، الفرق هنا هو أنّ الصنف يحتوي على دوال كذلك، وهذه الدوال تُسمى التّوابع، ويحتوي كذلك على مُتغيّرات وتنقسم هذه الأخيرة إلى نوعين، مُتغيّر الصنف، والمُتغيّر العادي، الفرق بينهما هو أنّك تستطيع الوصول إلى مُتغيّر الصنف في أي مكان داخل الصنف (سواء داخل التوابع أو خارجها). إنشاء صنف لإنشاء صنف في لغة بايثون كلّ ما عليك فعله هو كتابة كلمة class وبعدها اسم الصنف ثمّ إلحاق نقطتين، بعدها اكتب الشيفرة بإزاحة أربع مسافات: >>> class My_class: ... pass أنشأنا أعلاه صنفًا بسيطا باسم My_class وهو لا يفعل أي شيء يُذكر (كلمة pass تُخبر بايثون بالمرور دون تنفيذ أي شيء). إذا كتبت اسم الصنف على مفسّر بايثون فستجد مُخرجا كالتّالي: >>> My_class <class __main__.My_class at 0x7fd0efc41460> لاحظ بأنّ الكلمة الأولى من المُخرج هي class أي أنّنا أصبحنا نمتلك صنفًا جديدًا، ما يتبع at هو المكان في الذاكرة الذي وُضع فيه الصنف ويتغيّر بين الحين والآخر. إنشاء كائن من صنف بعد أن أنشأنا الصنف سنتمكّن الآن من إنشاء كائن من هذا الصنف، والكائن مُجرّد اسم تماما كالمُتغيّر: my_object = My_class() الآن الكائن my_object هو من صنف My_class. تعريف المتغيرات داخل صنف يُمكننا أن نُعرّف مُتغيّرات في الصنف تماما كما نُعرّف المُتغيّرات بشكل عادي. class My_class: my_variable = 'This is my variable' للوصول إلى المُتغيّر ننشئ أولا كائنا من الصنف وبعدها نكتب اسم الكائن ثمّ نقطة ثمّ اسم المُتغيّر: my_object = My_class() print my_object.my_variable المُخرج: This is my variable يُمكن كذلك الحصول على النّتيجة ذاتها في سطر واحد: print My_class().my_variable إنشاء التوابع التوابع هي دوال خاصّة بالصنف، ويُمكننا إنشاء التابع بنفس الطّريقة التي نُنشئ بها الدالة، الإختلاف هنا هو أنّ جميع التوابع يجب أن تُعرّف مع مُعامل باسم self وذلك للإشارة إلى أنّ الدالة/التابع تابع للصنف، لننشئ تابعا داخل صنف الآن. class My_class: my_variable = 'This is my variable' def my_method(self): print 'This is my method' الآن إذا أنشأنا كائنا فإنّنا سنتمكّن من الوصول إلى التابع، وتذكّر بأنّ التابع تلحقه الأقواس: my_object = My_class() my_object.my_method() المُخرج: This is my method يُمكن كذلك الحصول على النّتيجة ذاتها في سطر واحد: My_class().my_method() كما تُلاحظ فقد نُفّذت الشيفرة الموجودة داخل التّابع my_method ويُمكننا كذلك أن نجعل التّابع يقبل المُعاملات، لكن تذكّر الحفاظ على الكلمة self كمُتغيّر أول. class My_class: my_variable = 'This is my variable' def my_method(self, my_parameter): print 'This is my method ; {} is my parameter'.format(my_parameter) يُمكنك استدعاء التّابع كالتّالي: my_object = My_class() my_object.my_method('Parameter1') my_object.my_method('Parameter2') المُخرج: This is my method ; Parameter1 is my parameter This is my method ; Parameter2 is my parameter في البرنامج السّابق، أنشأنا أولا صنفًا باسم My_class وقُمنا بتعريف مُتغيّر، ثمّ بتعريف تابع باسم my_method يقبل مُعاملين self و my_parameter، بالنّسبة لاستدعاء التّابع، فنحتاج فقط إلى تمرير المُعاملات الموجودة بعد المُعامل selfولا نحتاج إلى تعيين قيمة لهذا المُعامل. مُلاحظة: يُمكنك إعادة تسميّة المُعامل الأول كما تشاء، أي أنّ البرنامج التّالي سيعمل دون مشاكل. class My_class: def my_method(this, my_parameter): print '{} is my parameter'.format(my_parameter) ولكن رغم ذلك فالمُتعارف عليه بين مُبرمجي لغة بايثون هو استعمال self، وفي كثير من اللغات الأخرى تُستعمل this عوضا عن self، أما في برامِجك فمن المُفضّل الإبقاء على هذه التّسميّة المُتعارف عنها، وذلك لتكون شيفراته سهلة القراءة. الوصول إلى متغيرات الصنف داخل التوابع تأمّل الصنف التّالي: class Person: lastname = 'Dyouri' job = 'Writer, Developer' def say_hello(self): name = 'Abdelhadi' print 'Hello, My name is {}'.format(name) البرنامج أعلاه بسيط جدا، أولا نعرّف صنف باسم Person وبعدها نقوم بتعيين قيمتين للمُتغيّرين name و lastname، وبعدها عرّفنا تابعا باسم say_hello يطبع جملة Hello, My name is Abdelhadi. كلّ شيء جيد، لكن ماذا لو أردنا أن نصل إلى المُتغيّرات الأخرى الموجودة خارج التّابع، فلا يُمكننا مثلا أن نقوم بالأمر كالتّالي: class Person: lastname = 'Dyouri' job = 'Writer, Developer' def say_hello(self): name = 'Abdelhadi' print 'Hello, My name is {}'.format(name) print lastname print job ستحصل على الخطأ التّالي: global name 'lastname' is not defined لتفادي هذا الخطأ سنستعمل كلمة self قبل المُتغيّر. class Person: lastname = 'Dyouri' job = 'Writer, Developer' def say_hello(self): name = 'Abdelhadi' print 'Hello, My name is {}'.format(name) print 'My Last name is {} '.format(self.lastname) print 'I am a {}'.format(self.job) استدعاء التّابع: me = Person() me.say_hello() المُخرج: Hello, My name is Abdelhadi My Last name is Dyouri I am a Writer, Developer لاحظ بأنّنا قُمنا بالوصول إلى مُتغيّر lastname عن طريق استدعائه بـ self.lastname وكذا الحال مع المُتغيّر job، وهذه الطّريقة مُشابهة لاستخدام كلمة global الفرق هنا أنّ هذه الأخيرة تُمكن من الوصول إلى المُتغيّر في كامل البرنامج، أمّا كلمة self فتُشير إلى المُتغيّر المُعرّف في الصنف الحاليّة فقط. لتفهم أكثر كيفيّة عمل الكلمة self فقط تخيّل بأنّها تحمل نفس اسم الصنف، مثلا: class Person: lastname = 'Dyouri' job = 'Writer, Developer' def say_hello(self): name = 'Abdelhadi' print 'Hello, My name is {}'.format(name) print 'My Last name is {} '.format(Abd.lastname) print 'I am a {}'.format(Abd.job) لاحظ بأنّنا غيّرنا كلمة self إلى اسم الصنف واستمرّ عمل البرنامج دون مشاكل. وبنفس الطّريقة يُمكنك أن تستدعي تابعا داخل تابع آخر في نفس الصنف: class Person: def say_name(self): print 'Abdelhadi' def say_hello(self): print 'Hello My name is:' self.say_name() المُخرج: Hello My name is: Abdelhadi ما حدث هو أنّ التّابع say_hello قام بطباعة جملة :Hello My name is ثمّ قام باستدعاء التّابع say_name الذي قام بدوره بطباعة الاسم Abdelhadi. لماذا تستعمل البرمجة الكائنية، ومتى يجب علي استخدامها قد تُلاحظ بأنّ ما يُمكنك فعله بالبرمجة الكائنيّة يُمكن القيام به بالدوال والمُتغيّرات فقط. هذا صحيح، وهو أمر واضح، البرمجة الكائنيّة تُستعمل أساسا إذا كان البرنامج الذي تبنيه مُعقّدا مع العديد من الوظائف المُتعلّقة ببعضها (كمكتبة برمجيّة)، مثلا لنقل بأنّك تُطوّر برنامجا مسؤولا عن جلب بيانات من موقع مُعيّن، وبعدها التّعديل عليها، ثمّ إخراج مستند PDF يحتوي على هذه البيانات بشكل يُسهّل قراءتها، هنا ستحتاج إلى صنف لجلب البيانات والتّعديل عليها، وصنف أخرى لتحويل البيانات إلى نصّ مقروء واضح ثمّ إلى ملفّ PDF. إذا نشرت برنامجك مع صديقك وأراد أن يعمل على الجزء الثاني لإضافة وظيفة تُمكن المُستخدم من طباعة المُستند فلا يُعقل أن يضطر للمرور على كل ما يتعلّق بجلب البيانات فقط لأنّه يريد أن يضيف خاصيّة لا علاقة لها بجلب البيانات. استعمال البرمجة الكائنيّة في هذا المشروع سيسمح لك بالتّركيز على الجزء الأول، وسيسمح لصديقك بالتّركيز على تطوير الجزء الثاني. خلاصة الأمر هي أنّك لست مضطرا لاستعمال البرمجة الكائنيّة إلا إذا كان برنامجك طويلا يحتوي على وظائف تتعلّق ببعضها البعض (وظائف من نفس الصنف)، ونسبة استخدام الآخرين لشيفرتك عالية. تمارين التمرين 1 أنشئ صنفًا باسمك، وقم بتعريف مُتغيّرين lastname (الاسم العائلي) و age (العمر)، ثم أنشئ كائنا باسم me (أنا) وقم بطباعة اسمك العائلي وعمرك. التمرين 2 أنشئ صنفًا باسم Car (سيارة) وقم بتعريف مُتغيّرات لصفات السّيارة، مثلا brand لاسم الشّركة، release_date لتاريخ الإعلان عن السّيارة. التمرين 3 أضف توابع إلى الصنف Car التي أنشأتها في التّمرين الثّاني، يُمكن أن تكون التوابع عبارة عن عمليّات تقوم بها السّيارة مثلا move للحركة، stop للتوقّف، slow_down لتخفيض السّرعة، وقم بطباعة جمل تفيد بأنّ العمليّة قد نجحت. المفروض أن يتمكّن الآخرون من إنشاء كائنات خاصّة بهم بحيث تُستخدم بهذه الطّريقة: bmw = Car() bmw.move() bmw.slow_down() bmw.stop() خاتمة تعرّفنا في هذا الدّرس على بعض من أهم أساسيات البرمجة الكائنيّة التوجه في لغة بايثون وهذا الموضوع أطول من أن أشرحه في درس واحد لذلك سيكون الدّرس التّالي تكملة لما تعلّمناه في هذا الدّرس حول تعلم بايثون وسيغطي مفاهيم أخرى حول البرمجة كائنية التوجّه.
-
مقدمة إلى المفهوم الكائني تُعتبر لغة سي شارب لغة برمجة كائنيّة صرفة pure object oriented programming language فكلّ ما تشاهده أمامك في سي شارب عبارة عن كائن. سيكون هذا الدّرس نظريًّا بعض الشيء ولكن فهمه بالشكل الصحيح يُعدّ أمرًا حيويًّا للبرمجة باستخدام سي شارب. ولنكن واقعيين، فإنّ هذا الدرس يُعتبر مدخلًا مبسّطًا للغاية إلى هذا الموضوع المهم والضخم ولا يمكن اعتباره بأيّ حال من الأحوال مرجعًا للبرمجة كائنيّة التوجّه. ستحصل -بعد قراءتك لهذا الدرس- على المعرفة الضروريّة للتمييز بين الأصناف classes والكائنات objects وفهم العلاقة بينهما. بالإضافة إلى فهم المبادئ الأوليّة للوراثة والتغليف. لكي نفهم ما هو الصنف وما هو الكائن اسمع منّي هذه القصّة: نتبع نحن البشر إلى ما يسمّى بالصنف الإنساني. يُعرّف هذا الصنف المزايا التي يجب أن يتمتّع بها كلّ إنسان. فمثلًا لكلّ إنسان اسم وطول ووزن ولون عينان وبصمة إبهام مميّزة تميّزه عن أيّ إنسان آخر. يُعرّف الصنف class الإنسانيّ هذه الصفات السابقة، بحيث أنّ كلّ كائن object إنسانيّ من هذا الصنف تكون له مثل هذه الصفات ولكنّ مع مجموعة خاصّة من القيم لها. فمثلًا الكائن من الصنف الإنساني هو إنسان قد يكون اسمه سعيد وطوله 180 سم ولون عينيه أسود وله بصمة إبهام مميّزة، وهذا الإنسان يختلف عن كائن إنسانيّ آخر، اسمه عمّار وطوله 175 سم ولون عينيه بنيّ وله أيضًا بصمة إبهام مميّزة خاصّة به، وهكذا. ندعو الصفات السابقة بالخصائص Properties، فالصنف Class يعرّف الخصائص، أمّا الكائن Object فيتمتّع بهذه الخصائص ولكن مع مجموعة قيم لها تميّزه عن كائنٍ آخر. أمر آخر، يُعرّف الصنف الإنساني أيضًا سلوكيّات أو إجراءات معيّنة خاصّة للكائنات التي تعود للصنف الإنسانيّ. فهناك مثلًا سلوكيّات المشي والجري والضحك. وفي الغالب أنّ كل كائن يُعبّر عن هذه السلوكيّات بشكل يراعي خصوصيّته. فلكلّ منّا أسلوب مختلف في الضحك. كما يمتلك كلّ منّا أسلوب مختلف في المشي والجري، فقد تميّز إنسانًا لا ترى وجهه من خلال مشيته فقط وهذا أمر واردٌ جدًّا. مثل هذه السلوكيّات Methods نصطلح عليها في البرمجة بالتوابع. فالصنف الإنسانيّ يُعرّف وجود مثل هذه السلوكيّات ولكلّ كائن إنسانيّ الحريّة في التعبير عن هذه السلوكيّات بالشكل الذي يرغبه. التابع في البرمجة يضم تعليمات برمجية يجري تنفيذها عند استدعائه. يعالج ويتعامل هذا التابع عادةً مع الخصائص والتوابع الأخرى الموجودة ضمن نفس الكائن. نسمي التوابع والخصائص بأعضاء الصنف class members وهناك أعضاء أخرى سنتناولها في الدروس التالية. المبادئ العامة للمفهوم كائني التوجه هناك المئات من المقالات والكتب التي تتحدّث عن المفهوم الكائنيّ من منظورات مختلفة، وهناك أساليب متعدّدة تسمح بتحليل المسألة المطروحة وتصميمها وفق أسلوب كائنيّ أو ما يُعرف بالتصميم والتحليل كائنيّ التوجّه OOAD. ولكن يكفيك أن تعرف الآن أنّ هناك مبدآن أساسيّان ينبغي أن تتمتّع بها أيّ لغة برمجة تدعم المفهوم كائنيّ التوجّه وهما: التغليف Encapsulation والوراثة Inheritance. وهناك مفهوم مهم آخر يستند إلى الوراثة وهو التعدّديّة الشكلية Polymorphism. التغليف Encapsulation وهو مبدأ جوهري في البرمجة كائنيّة التوجّه، وهو أحد أسباب ظهور هذا المفهوم. يُقرّر هذا المبدأ أنّه ليس من المفترض أن نطّلع على آلية العمل الداخلية للكائن. ما يهمنا هو استخدام الكائن وتحقيق الغرض المطلوب بصرف النظر عن التفاصيل الداخليّة له. تأمّل المثال البسيط التالي: عندما نقود السيّارة ونريد زيادة سرعتها فإنّنا بكلّ بساطة نضغط على مدوسة الوقود. لا أعتقد أنّ أحدًا يهتمّ بالآلية الميكانيكيّة التي تقف وراء الضغط على مدوسة الوقود. فالمطلوب هو زيادة سرعة السيّارة فحسب دون الاهتمام بالتفاصيل الداخليّة. فالسيّارة تُغلّف encapsulate التفاصيل الميكانيكيّة الداخليّة التي تقف وراء زيادة سرعة السيّارة. السيّارة في هذا المثال هو كائن Object. وعمليّة زيادة السرعة هي سلوكيّة (تابع) Method من كائن السيّارة. هناك مثال آخر كثيرًا ما نراه أثناء تجوّلنا في الشوارع ومحطّات القطار وصالات الانتظار، وهو آلات تحضير المشروبات الساخنة. نقف أمام الآلة نُدخل النقود ثمّ نضغط على زرّ محدّد لنحصل على المشروب الساخن الذي نرغب به. لا نهتمّ عادةً بالتفاصيل الداخليّة التي تحدث ضمن الآلة عندما نضغط أحد الأزرار للحصول على كوب من القهوة. فالآلة هنا تُعتبر كائنًا، وعمليّة الحصول على كوب من القهوة هي سلوكيّة Method من هذا الكائن. فهذه الآلة تعمل على تغليف encapsulate التفاصيل الداخليّة لعمليّة التحضير، فكلّ ما نفعله هو ضغط الزر ومن ثمّ نحصل على الناتج المطلوب. فإذا ما أُجري تعديل في الآلة بحيث تتغيّر طريقة تحضير مشروب ساخن لجعله أفضل وأكثر لذّة، فإنّ ذلك لن يؤثّر مطلقًا على أسلوب التعامل مع الآلة للحصول على نفس المشروب، ولن نلاحظ هذا التعديل إلّا بعد تذوّقنا للمشروب وملاحظة الفرق في المذاق. الوراثة Inheritance تُعتبر الوراثة من أهم أشكال إعادة الاستخدام للمكوّنات البرمجيّة، حيث يعمل الصنف الجديد على الاستفادة من المكوّنات الموجودة مسبقًا ضمن الصنف الذي "يرث" منه ويجري عليها بعض التعديلات التي تناسبه على نحو مخصّص. فبدلًا من إنشاء صنف جديد من الصفر، يمكننا إنشاء صنف يعتمد على صنف آخر ويستفيد من خصائصه وسلوكيّاته (توابعه) الموجودة مسبقًا ثمّ يكيّفها أو يضيف عليها. نسمّي الصنف الأساسي الذي نرث منه بالصنف الأب. أمّا الصنف الذي يقوم بعمليّة الوراثة فنسمّيه بالصنف الابن أو بالصنف المشتق. لتثبيت الفكرة لنتناول المثال التالي. في المدارس هناك ثلاثة أنواع أساسيّة من الأشخاص المتواجدين فيها: الطلاب والمدرّسون والإداريّون. يمكننا بناء صنف عام يُمثّل أي شخص يعمل في المدرسة وليكن SchoolMember يحتوي هذا الصنف على خصائص مثل: الاسم والكنية واسم الأب واسم الأم وتاريخ الميلاد ورقم الهاتف. يمكننا البناء على هذا الصنف عندما نريد إنشاء أصناف أكثر "تخصّصًا" منه. مثل الصنف الذي يُعبّر عن الطلاب Student والصنف الذي يُعبّر عن المدرّسين Teacher، والصنف المُعبّر عن الإداريين Staff. يرث كلّ صنف منها من الصنف الأب SchoolMember فيصبح لكلّ منها نفس الخصائص الموجودة ضمن الصنف SchoolMember بشكل تلقائيّ. من الواضح أنّ الصنف Student مخصّص أكثر من الصنف SchoolMember فهو يحتوي بالإضافة إلى الخصائص الموجودة في SchoolMember خصائص فريدة خاصّة به. فمثلًا من الممكن أن يحتوي على الخاصيّة التي تعبّر عن الصفّ الحالي Grade وعن السلوك العام Behavior للطالب، أمّا صنف المدرّس Teacher فمن الممكن أن يحتوي (بالإضافة إلى الخصائص الموجودة ضمن SchoolMember) على خاصيّة Course التي تُعبّر عن المقرّر الذي يدرّسه (رياضيّات، فيزياء ...الخ) والخاصيّة WeeklyHours التي تعبّر عن عدد الساعات التدريسيّة الأسبوعيّة المكلّف بها. وينطبق نفس المفهوم تمامًا على الصنف Staff الذي يعبّر عن الموظّفين الإداريين في المدرسة. فالوراثة تنتقل بنا من الشكل الأكثر عموميّةً SchoolMember إلى الشكل الأكثر تخصيصًا مثل Student. وفي الحقيقة كان من الممكن أن نتابع عمليّة الوراثة اعتبارًا من الصنف Staff فهناك قسم التوجيّه وهناك أمانة السر والإدارة وغيرها، وكلّ منها يمكن أن يرث من الصنف Staff. التعددية الشكلية Polymorphism بفرض أنّنا نريد بناء برنامج يحاكي الحركة الانتقاليّة لعدّة أنواع من الحيوانات لدراسة حيويّة. كلّ من أصناف السمكة Fish والطائر Bird والضفدع Frog ترث من الصنف Animal الذي يمثّل أيّ حيوان. بفرض أنّ الصنف Animal يحتوي على سلوكيّة (تابع) اسمها Move (تُعبّر عن الانتقال)، فكما نعلم أنّ هذه السلوكيّة ستصبح وبشكل تلقائي موجودة ضمن أيّ صنف يرث من الصنف Animal، وهنا تكمن التعدديّة الشكليّة. فكل صنف من الأصناف Fish وBird وFrog يُعبّر عن عملية الانتقال Move بشكل مختلف. فالسمكة ربما تنتقل عن طريق السباحة مترًا واحدًا عند استدعاء التابع Move. أمّأ الطائر Bird فمن الممكن أي يطير مسافة 10 متر عند كل استدعاء للتابع Move، وأخيرًا فإنّه من الممكن للضفدع أن يقفز مسافة 20 سنتيمتر كلّما استدعي التابع Move. فالتابع Move المعرّف ضمن الصنف Animal يمكن التعبير عنه بأشكال متعدّدة ضمن الأصناف الأبناء Fish وBird وFrog كلٌّ بحسب حاجته. الخلاصة تعرّفنا في هذا الدرس على المفهوم العام للبرمجة كائنيّة التوجّه وتعاملنا مع التغليف حيث لا تهمّنا التفاصيل الداخلية لآلية العمل. والوراثة التي تتعلّق بمفهوم إعادة الاستخدام والانتقال من العام (الأب) إلى المخصّص (الابن). بالإضافة إلى التعدديّة الشكليّة التي تسمح لنا بإكساب سلوكيّات مخصّصة للأصناف الأبناء تنسجم مع طبيعتها. سنتناول في الدروس التالية هذه المفاهيم بشكل تطبيقي في سي شارب.
-
سنتحدّث في هذا الدرس عن كيفيّة تطبيق مبادئ البرمجة كائنيّة التوجّه في سي شارب وذلك من خلال إنشاء واستخدام الأصناف والكائنات في هذه اللغة. يمكن التصريح عن صنف في سي شارب باستخدام الكلمة المحجوزة class يليها اسم الصنف وهو يتبع لنفس قواعد التسمية للمتغيّرات، علمًا أنّه يفضّل أن يكون الحرف الأوّل من اسم الصنف حرفًا طباعيًّا كبيرًا. انظر إلى الشكل التالي حيث نرى الصنف البسيط Employee والذي يُعبّر عن موظّف في إحدى الشركات: يحتوي هذا الصنف على ثلاثة حقول بيانات data fields هي: الاسم FirstName الكنية LastName الراتب Salary تستطيع اعتبارها حاليًّا أنّها تمثّل خصائص للصنف Employee، كما يحتوي هذا الصنف على تابع وحيد اسمه DisplayInfo الهدف منه هو الحصول على تمثيل نصيّ لكلّ كائن ننشئه من هذا الصنف كما سنرى بعد قليل، يشبه التابع إلى حدٍّ كبير الدّالة function في لغات البرمجة الأخرى. لا يتطلّب هذا التابع أيّ وسائط في حين أنّه يُرجع قيمة نصيّة من النوع string. هذه الحقول بالإضافة إلى التابع السابق تُعتبر أعضاء ضمن الصنف Employee كما ذكرنا ذلك مسبقًا. تقع أعضاء أيّ صنف ضمن حاضنتيه. لاحظ الكلمة المحجوزة public والموجودة قبل كلّ تصريح لحقل أو تابع ضمن الصنف Employee. هذه الكلمة عبارة عن مُحدّد وصول access modifier. تتحكّم محدّدات الوصول بقابلية الوصول إلى أعضاء الصنف من خارجه، سنتعامل مع نوعين آخرين من محدّدات الوصول وهما private و protected. يكفي أن تعلم الآن أنّ أي عضو في الصنف يمتلك محدّد وصول public يمكن الوصول إليه سواءً من داخل الصنف (أو بشكل أدق من داخل الكائن) أو من خارجه. كما من المفيد أن نعلم أنّه من الممكن استخدام محدّدات الوصول مع الأصناف أيضًا كما سنرى في درس لاحق. إذا أردنا إنشاء كائن جديد من الصنف Employee فعلينا التصريح عن متغيّر مناسب من النوع Employee وذلك على الشكل التالي: Employee empObject; صرّحنا عن المتغيّر empObject على أنّه من النوع Employee. لاحظ التشابه في التصريح عن المتغيّرات بين أنواع موجودة ضمن سي شارب وبين أنواع ننشئها بأنفسنا. التصريح السابق غير كافي لإنشاء الكائن. لإنشاء كائن من النوع Employee علينا استخدام العامل new الذي يعمل على إنشاء كائن من أيّ صنف نرغبه ويعمل على إعادة المرجع (العنوان) لذلك الكائن في الذاكرة. استخدام العامل new سهل حيث يمكننا كتابة ما يلي بعد عبارة التصريح السابقة: empObject = new Employee(); يقوم العامل new بإنشاء كائن جديد من الصنف Employee ثمّ يُسند مرجع (عنوان) هذا الكائن ضمن المتغيّر empObject. لاحظ القوسين الموجودين بعد اسم الصنف Employee. في الحقيقة يُعبّر هذين القوسين عن استدعاء لبانية constructor الصنف Employee عند إنشاء الكائن. ولكن أين هذه البانية؟ هذا ما سنراه بعد قليل. يمكن الآن الوصول إلى الحقول والتوابع الموجودة ضمن الكائن عن طريق كتابة المتغيّر الذي يحوي العنوان إلى الكائن (أي المتغيّر empObject) ثم نضع نقطة وبعدها اسم الحقل أو التابع الذي نريد الوصول إليه. في العبارة التالية سنسند القيمة "Mohammad" إلى الحقل FirstName من الكائن empObject (الكائن الذي يشير إليه empObject): empObject.FirstName = "Mohammad"; حان الآن وقت التنفيذ العمليّ. انظر إلى البرنامج Lesson06_01 الذي يوضّح كيفية إنشاء الصنف Employee وكيفيّة إنشاء كائنين منه: 1 using System; 2 3 namespace Lesson06_01 4 { 5 6 class Employee 7 { 8 public string FirstName; 9 public string LastName; 10 public double Salary; 11 12 public string DisplayInfo() 13 { 14 string result = string.Format("{0} {1} - Salary: {2:N0}", 15 this.FirstName, this.LastName, this.Salary); 16 17 return result; 18 } 19 } 20 21 class Program 22 { 23 static void Main(string[] args) 24 { 25 Employee employee1, employee2; 26 27 employee1 = new Employee(); 28 employee1.FirstName = "Mohammad"; 29 employee1.LastName = "Mansoor"; 30 employee1.Salary = 1000; 31 32 employee2 = new Employee(); 33 employee2.FirstName = "Saleh"; 34 employee2.LastName = "Mahmoud"; 35 employee2.Salary = 2500; 36 37 Console.WriteLine("First Employee: {0}", employee1.DisplayInfo()); 38 Console.WriteLine("Second Employee: {0}", employee2.DisplayInfo()); 39 } 40 } 41 } عند تنفيذ البرنامج سنحصل على الخرج التالي: First Employee: Mohammad Mansoor - Salary: 1,000.00 Second Employee: Saleh Mahmoud - Salary: 2,500.00 نلاحظ من النظرة الأولى للبرنامج السابق أنّه لدينا صنفان ضمن نطاق الاسم Lesson06_01 وهما Employee و Program. يقع التصريح عن الصنف Employee في الأسطر بين 6 و 19 ويحتوي هذا الصنف كما رأينا قبل قليل على أربعة أعضاء وهي عبارة عن ثلاثة حقول FirstName و LastName و Salary بالإضافة إلى التابع DisplayInfo الموجود بين السطرين 12 و18. تنحصر وظيفة هذا التابع في الحصول على التمثيل النصيّ لأيّ كائن ننشئه من الصنف Employee. يحتوي التابع DisplayInfo على أسلوب جميل لتنسيق النصوص يشبه ذلك الأسلوب الذي كنّا نستخدمه مع التابع WriteLine. يحتوي الصنف string على تابع اسمه Format يقبل عدّة وسائط (السطر 14) أولها نصّ تنسيقي، أمّا الوسائط التالية فهي القيم التي ستجد لها أمكنةً ضمن النص التنسيقي، كما كنّا نستخدم التابع WriteLine بالضبط. يُرجع التابع Format نصًّا منسّقًا بحسب القيم الممرّرة له. الشيء الوحيد المختلف هو كيفيّة تنسيق قيمة الراتب Salary باستخدام مُحدّد التنسيق :N0 الموجود ضمن {2:N0}. يخبر هذا المحدّد التابع Format أنّ القيمة التي ستوضع في هذا المكان (وهي قيمة Salary) يجب أن تُنسّق على شكل رقم ذي فاصلة آلاف وبدون فاصلة عشريّة. يفيد مثل هذا التنسيق في الحصول على أرقام منسّقة بشكل محترف تُعبّر عن الراتب الذي يحصل عليه الموظّف وهي تبدو مثل 1,000 أو 2,500. جرّب استخدام التنسيق {2:N1} و {2:N2} ولاحظ الفرق. لاحظ أنّني قد استخدمت الكلمة المحجوزة this متبوعةً بنقطة قبل اسم كل حقل. في الحقيقة تُشير هذه الكلمة إلى الكائن الحالي الذي يتمّ منه استدعاء التابع DisplayInfo كما سنرى ذلك بعد قليل. أمّا لإرجاع القيمة النصيّة من التابع DisplayInfo فإنّنا ببساطة نستخدم الكلمة المحجوزة return ونضع بعدها القيمة المراد إرجاعها. الصنف Program المصرّح عنه في الأسطر بين 21 و 40 هو الصنف الذي تعاملنا معه في جميع البرامج التي كتبناها حتى الآن. يحتوي هذا الصنف على التابع Main الذي يمثّل نقطة الدخول للبرنامج كما نعلم. يبدأ التابع Main بالتصريح عن متغيرين من النوع Employee وهما employee1 و employee2 ثمّ ينشئ كائنًا من النوع Employee باستخدام العامل new (السطر 27) ويسنده إلى المتغيّر employee1. بعد ذلك يمكن استخدام أيّ حقل أو تابع معرّف ضمن الصنف Employee عن طريق المتغيّر employee1 بشرط أن يكون له محدّد وصول public كما هو واضح في الأسطر من 28 حتى 30. يتكرّر نفس الأمر بالنسبة للمتغيّر employee2 الذي سيحمل كائنًا مختلفًا عن الكائن الموجود ضمن employee1. أخيرًا وفي السطرين 37 و38 يتم طباعة التمثيل النصيّ لكلّ من الكائنين باستخدام التابع DisplayInfo. تجدر الإشارة إلى أنّه عند وصول تنفيذ البرنامج إلى السطر 37 وإلى الاستدعاء ()employee1.DisplayInfo تحديدًا سيؤدّي ذلك إلى انتقال التنفيذ إلى السطر 14 ضمن هذا التابع لتنفيذ التعليمات البرمجيّة ضمنه ومن ثمّ الحصول على التمثيل النصيّ للكائن employee1 وإرجاعه إلى السطر 37 مرّة أخرى ليعمل البرنامج على تمرير هذه القيمة النصيّة للتابع WriteLine ومن ثمّ العرض على الشاشة، وبالطبع يتكرّر نفس الأمر تمامًا بالنسبة للكائن ضمن employee2 في السطر 38. إذا كنت تستخدم Visual Studio 2015 بأيّ إصدار فأنصحك أن تنفّذ هذا البرنامج بشكل خُطَوي لكي تتعرّف على آلية عمل هذا البرنامج بشمل عمليّ. اضغط على المفتاح F11 (أو من القائمة Debug > Step Into) لتنفيذ البرنامج باستخدام منقّح الأخطاء debugger. ستلاحظ ظهور مستطيل أصفر يُشير إلى مكان التنفيذ الحالي، وكلما ضغطت المفتاح F11 سينتقل تنفيذ البرنامج إلى العبارة البرمجيّة التالية خطوة بخطوة. البانية constructor ضمن الصنف البانية constructor هي تابع من نوع خاص يجب أن تكون موجودة ضمن أيّ صنف في سي شارب. في حال تمّ إغفالها سيعمل المترجم على توليد واحدة افتراضيّة من أجلنا. في الحقيقة وظيفة البانية هي بناء الكائن وحجز مكان مناسب له في الذاكرة، حيث يتم استدعاء البانية عند إنشاء الكائن باستخدام العامل new. لا يمكن للبواني إرجاع قيمة مخصّصة كما نفعل مع التوابع الأخرى عادةً، في الحقيقة هي تُرجع كائنًا من الصنف الموجودة ضمنه. ولكن يمكن أن تقبل وسائط نمرّرها إليها. استبدل الصنف Employee التالي بذلك الموجود ضمن البرنامج Lesson06_01: 1 class Employee 2 { 3 public string FirstName; 4 public string LastName; 5 public double Salary; 6 7 public Employee() 8 { 9 Console.WriteLine("Hello, I'm in Employee's constructor!"); 10 } 11 12 public string DisplayInfo() 13 { 14 string result = string.Format("{0} {1} - Salary: {2:N0}", 15 this.FirstName, this.LastName, this.Salary); 16 17 return result; 18 } 19 } لقد أضفنا في هذه النسخة البانية ()Employee للصنف Employee. نفّذ البرنامج لتحصل على الخرج التالي: *** Hello, I'm in Employee's constructor! *** *** Hello, I'm in Employee's constructor! *** First Employee: Mohammad Mansoor - Salary: 1,000 Second Employee: Saleh Mahmoud - Salary: 2,500 لاحظ أنّ العبارة: *** Hello, I'm in Employee's constructor! *** قد ظهرت مرّتين في الخرج، وذلك بسبب أنّنا أنشأنا كائنين حيث تُنفّذ هذه البانية من أجل كلّ عملية إنشاء. ولكن السؤال المطروح هنا، ماذا سنستفيد من هذه البانية؟ تُستخدم البواني عمومًا عندما نريد تهيئة الكائن ببعض القيم الضرورية لجعل حالته مستقرّة وذلك أثناء إنشائه وقبل محاولة الوصول إليه من أيّ مصدر خارجيّ. انظر الآن إلى الصنف Employee المعدّل الذي يحوي بانية تقوم ببعض الأعمال المفيدة: 1 class Employee 2 { 3 public string FirstName; 4 public string LastName; 5 public double Salary; 6 7 public Employee(string firstName, string lastName, double salary) 8 { 9 this.FirstName = firstName; 10 this.LastName = lastName; 11 this.Salary = salary; 12 } 13 14 public string DisplayInfo() 15 { 16 string result = string.Format("{0} {1} - Salary: {2:N0}", 17 this.FirstName, this.LastName, this.Salary); 18 19 return result; 20 } 21 22 } تتطلّب البانية هذه المرّة ثلاثة وسائط، تمثّل قيمًا سيتمّ إسنادها إلى الحقول. هذه الوسائط هي: firstName و lastName و salary (لاحظ أنّ اسم كلّ منها يبدأ بحرف طباعي صغير لتمييزها عن حقول الصنف). إذا استبدلت هذا الصنف الجديد بالصنف القديم الموجود ضمن البرنامج Lesson06_01 وحاولت تنفيذ البرنامج فستحصل على خطأ. السبب في ذلك بسيط، وهو أنّ العبارتين في السطرين 27 و 32 من البرنامج Lesson06_01 تحاولان إنشاء كائنين من الصنف Employee عن طريق بانية لا تتطلّب أيّة وسائط وهذا ما لا يتوفّر في الصنف Employee الجديد. فعندما يلاحظ مترجم سي شارب وجود بانية واحدة على الأقل بصرف النظر عن عدد الوسائط التي تتطلّبها فإنّه يمتنع عن توليد بانية افتراضية بشكل تلقائي مثلما كان يفعل من قبل. يوجد حلّ سريع لهذه المشكلة يتمثّل في توفير بانية لا تحتاج لأيّة وسائط كما كان الوضع السابق. انظر إلى النسخة الأخيرة للصنف Employee: 1 class Employee 2 { 3 public string FirstName; 4 public string LastName; 5 public double Salary; 6 7 public Employee(string firstName, string lastName, double salary) 8 { 9 this.FirstName = firstName; 10 this.LastName = lastName; 11 this.Salary = salary; 12 } 13 14 public Employee() 15 { 16 17 } 18 public string DisplayInfo() 19 { 20 string result = string.Format("{0} {1} - Salary: {2:N0}", 21 this.FirstName, this.LastName, this.Salary); 22 23 return result; 24 } 25 26 } بعد اعتماد هذا الصنف ضمن البرنامج Lesson06_01، سيعمل البرنامج الآن بشكل طبيعي ويظهر الخرج كما هو متوقّع. ولكن تأمّل معي هذا الصنف قليلًا، ألا تلاحظ وجود بانيتين له؟ هذا أمر طبيعي ووارد جدًّا في سي شارب حيث يمكن كتابة أكثر من تابع بنفس الاسم طالما اختلف عدد أو أنواع الوسائط الممرّرة لكلّ منهما. نسمي هذه الميزة بزيادة التحميل overloading للتوابع. فعند وجود استدعاء للتابع المزاد تحميله يتمّ اختيار الشكل المناسب بناءً على عدد وأنواع الوسائط الممرّرة. لاحظ أنّ البانية عديمة الوسائط فارغة ولا بأس في ذلك. ولكنّ السؤال هنا كيف يمكن الاستفادة من البانية ذات الوسائط الثلاثة. الأمر بسيط، استبدل محتويات التابع Main في البرنامج Lesson06_01 بالشيفرة البسيطة المكافئة التالية: 1 Employee employee1, employee2; 2 3 employee1 = new Employee("Mohammad", "Mansoor", 1000); 4 employee2 = new Employee("Saleh", "Mahmoud", 2500); 5 6 Console.WriteLine("First Employee: {0}", employee1.DisplayInfo()); 7 Console.WriteLine("Second Employee: {0}", employee2.DisplayInfo()); انظر كم أصبحت الشيفرة نظيفة وقصيرة ومريحة للعين. إليك الآن البرنامج Lesson06_02 كاملًا بعد التعديل: 1 using System; 2 3 namespace Lesson06_02 4 { 5 6 class Employee 7 { 8 public string FirstName; 9 public string LastName; 10 public double Salary; 11 12 public Employee(string firstName, string lastName, double salary) 13 { 14 this.FirstName = firstName; 15 this.LastName = lastName; 16 this.Salary = salary; 17 } 18 19 public Employee() 20 { 21 22 } 23 24 public string DisplayInfo() 25 { 26 string result = string.Format("{0} {1} - Salary: {2:N0}", 27 this.FirstName, this.LastName, this.Salary); 28 29 return result; 30 } 31 32 33 } 34 35 36 class Program 37 { 38 static void Main(string[] args) 39 { 40 Employee employee1, employee2; 41 42 employee1 = new Employee("Mohammad", "Mansoor", 1000); 43 employee2 = new Employee("Saleh", "Mahmoud", 2500); 44 45 Console.WriteLine("First Employee: {0}", employee1.DisplayInfo()); 46 Console.WriteLine("Second Employee: {0}", employee2.DisplayInfo()); 47 } 48 } 49 } تمارين داعمة تمرين 1 أضف تابعًا جديدًا إلى الصنف Employee الموجود في البرنامج Lesson06_02 السابق وسمّه GetSalaryAfterTax. وظيفة هذا التابع هي الحصول على قيمة الراتب للموظّف بعد تطبيق الضريبة Tax عليه. اعتبر نسبة الضريبة 2%. تلميح: اضرب قيمة الراتب Salary بالعدد 0.98 للحصول على قيمة الراتب بعد خصم الضريبة. فإذا كان الراتب 1500 مثلًا، يجب أن يُرجع التابع GetSalaryAfterTax القيمة 1470. تمرين 2 أنشئ صنفًا جديدًا سمّه MyRectangle والذي يُعبّر عن مستطيل في المستوي، بحيث يحتوي على الحقلين Width و Height (من النوع double لكلّ منهما)، بالإضافة إلى التابع GetArea لحساب مساحة المستطيل. ثمّ اكتب برنامجًا بسيطًا يوضّح استخدام هذا الصنف من خلال إنشاء كائنين منه. احسب مساحة كل مستطيل (كائن) واعرض النتيجة على الشاشة. الخلاصة تعلّمنا في هذا الدرس أساسيّات إنشاء الأصناف والكائنات، وكيفية التعامل مع الحقول والتوابع والبواني الموجودة ضمن الصنف. كما أخذنا لمحة سريعة حول محدّدات الوصول وكيفية التعامل مع محدّد الوصول public، علمًا أنّنا ستوضّح كيفيّة التعامل مع باقي المحدّدات في الدرس التالي الذي سنتحدّث فيه عن المزيد حول هذا الموضوع المهم والأساسي لتطوير التطبيقات باستخدام سي شارب.
-
توجد طرق متعددة لصنع تطبيقات لنظام تشغيل أندرويد ويُفضل المطوَرون كتابة التطبيقات باستخدام اللغة الرسمية وهي جافا لقدرتها على استغلال كافة موارد الهاتف وكفاءتها عند العمل. وتُستخدم لغات البرمجة لإعطاء الأوامر للحاسوب لتنفيذها وتتشابه مع اللغات الحقيقية في أنها بدلًا من أن تتواصل مع البشر فهي تتواصل مع الحاسوب ووصف الطريقة التي أرغب أن يعمل بها. يعتمد نظام تشغيل أندرويد على أساسيات لغة جافا ومكتباتها القوية بالإضافة إلى مكتبات أندرويد الخاصة، ويتم وضع الشيفرة المكتوبة بلغة جافا بعد أن يتم ترجمتها إلى صيغتها التنفيذية في ملف بامتداد apk جنبًا إلى جنب مع باقي الموارد من صور وملف androidManifest. البرمجة كائنية التوجه تتميز لغة جافا بأنها لغة سهلة التعلم وتٌصنف من اللغات عالية المستوى والتي نستطيع فهم أوامرها بسهولة، وهي من لغات البرمجة التي تدعم مفهوم البرمجة كائنية التّوجّه. والبرمجة كائنية التّوجّه تتكون من مجموعة من المفاهيم. في عالمنا الحقيقي يمكن التعامل مع أي شيء على أنه كائن، ولكل كائن صفات تميزه ولديه وظائف يستطيع القيام بها، فمثلًا الكاميرا كائن لها صفات مثل اللون والأبعاد والشركة المصنعة لها، ولها وظائف يستطيع القيام بها مثل التصوير أو تخزين وعرض الصورة. ويوجد أنواع عديدة من الكاميرات لذا يتم وضع التصميم المشترك والتعريف الخاص بهذه الكائنات في البرمجة في صنفClass ومن هذا الصّنف يتم استخراج الكائنات. لذا يتم تصّنيف الأشياء إلى فئات تشترك في الصفات والوظائف ومنها يتم صنع الكائنات Objects. المتغيرات تتعامل لغة جافا مع كافة أنواع البيانات والقيام عليها بالعمليات المختلفة. لذا تستخدم المتغيرات كحاويات لتخزين هذه البيانات لحفظها بشكل مؤقت والقيام عليها بالعمليات المطلوبة ويمكن تغيير هذه القيم في أي وقت ويعتبر تعريف المتغيرات الطريقة لجعل الحاسوب يحتفظ بالمعلومات. عند تعريف متغير جديد يجب تحديد ما هو نوع البيانات التي يستطيع المتغير تخزينها بداخله، قد تكون البيانات اسمًا أو أرقامًا أو رابط لفيديو أو صورة لذا يجب تحديد نوع البيانات التي سيحتويها المتغير حتى يستطيع البرنامج التعامل معها بشكل صحيح. فإذا كان المتغير رقمًا فلا يمكن أن نخزن به نصًا. ولتعريف متغير جديد يتم على هذا النحو: DataType variableName; يتم كتابة نوع البيانات أولًا ثم اسم المتغير، واسم المتغير يمكن أن يكون أي شيء ولكن هناك بعض الأمور التي يجب مراعاتها وهي: يمكنك استخدام الحروف "A-Z" و "a-z" و "0-9". ألا يبدأ برقم. لا يسمح باستخدام أي حروف خاصة في الاسم مثل @، # وغيرهما عدا _ فقط. لا يسمح باستخدام المسافات في الاسم. ألا يكون الاسم من الكلمات المجوزة لدى اللغة وهي كلمات ذات معنى محدد لدى المترجم. أنواع البيانات هناك بعض الأنواع الأساسية لتعريف المتغيرات مثل: الأرقام الصحيحة: يتم تخزين الأرقام الصحيحة في متغير النوع int. int number=26; الأرقام الكسرية: لتخزين الأرقام الكسرية نستخدم متغير من النوع float أو double. double fraction=102.486; float fraction=842.014f; لاحظ أن عند تعريف متغير من النوع float يجب وضع الحرف f في نهاية الرقم. الحروف: لتخزين حرف واحد نستخدم متغير من النوع char. char c=’y’; char num=’8’; char s=’&’; يتم وضع الحرف بين علامتيّ اقتباس فردية. القيم المنطقية: لتخزين متغير يحمل إحدى القيمتين المنطقيين true أو false يتم تعريف متغير من النوع boolean، ويستخدم في المقارنات المنطقية. boolean flag=true; النصوص: لتخزين نص يتم استخدام متغير من النوع String. String str=”Hello,World!!”; يتم وضع النص بين علامتيّ اقتباس زوجية ولا يوجد حد لطول النص. والاختلاف بين النوعين char و String أن الأول لتخزين حرف واحد فقط والثاني لنص كامل، ولاحظ أن علامتيَ الاقتباس مختلفة فلا يمكن استخدام "R" لتخزينها في متغير من النوع char لأنها داخل علامتيّ الاقتباس الخاصة بالنص. كما يمكنك أن تقوم بتعريف المزيد من أنواع البيانات باستخدام الأصناف كما سنرى لاحقًا. في الأمثلة السابقة قمنا بتعريف المتغير وتخزين قيمة مبدئية بداخله، هناك طريقة أخرى يمكن استخدامها كما في المثال التالي. int x; x=100; في المثال السابق تم تعريف متغير اسمه x ثم قمنا لاحقًا بتخزين قيمة بداخله ويمكن تغيير القيمة بعد ذلك في أي وقت داخل البرنامج، وبالمثل يمكن تعريف باقيِ أنواع المتغيرات بهذه الطريقة. ملاحظات تنتهي الجمل في جافا بالفاصلة المنقوطة ";" للتعبير عن انتهاء الجملة، ويمكن اعتبارها مثل النقطة التي تنتهي بها الجملة عند الكتابة. العلامة "=" تسمى بـ "عامل الإسناد" (Assignment Operator) وتستخدم لتخزين القيم التي تقع يمين العامل في المتغير الذي يقع على يساره. int x; x=3; x=x+5; في هذا المثال سيتم تخزين 3 في المتغير x ثم بعد ذلك جمع عليه الرقم 5 وتخزينه مرة أخرى في x ليصبح الناتج النهائي المخزن داخل المتغير x يساوي 8. العمليات الحسابية والمنطقية العمليات الرياضية يمكننا القيام بالعمليات الرياضية المعتادة في لغة جافا فمثلًا: int x = 19; int y = 4; int result = x + y; وهنا يتم جمع قيم المتغيرين وتخزينهما في المتغير result ليصبح الناتج يساوي 23: int result = x – y; وإذا قمنا بتغيير السطر الثالث بهذا السطر فيصبح الناتج 15: int result = x * y; وناتج ضربهما يساوي 76: int result = x / y; وناتج القسمة يساوي 4 ويتم إهمال الكسر لأن في لغات البرمجة عندما نقوم بقسمة رقمين صحيحين فيكون الناتج رقمًا صحيحًا. int result = x % y; وتعني هذه العملية بباقي قسمة x على y وتساوي 5. وهناك العملية: x++; وهي تتشابه مع: x=x+1; فهي تقوم بزيادة واحد على قيمة المتغير، وبالمثل العملية --x تقوم بطرح واحد من قيمة المتغير. عمليات المقارنة وتقارن هذه العمليات بين المعاملات مثل: int a = 15; int b = 20; boolean result = a > b; وتقوم هذه العملية بالمقارنة بين قيمتيّ a و b وتخزين true أو false في المتغير result وفي المثال السابق سيتم تخزين false لأن b ذات قيمة أكبر من a. وباقي المقارنات هي > أصغر من، و =< أكبر من أو يساوي، => أصغر من أو يساوي، == يساوي، =! لا يساوي وكلهم يكون ناتجهم إما true أو false. العمليات المنطقية تستخدم العمليات المنطقية في ربط ناتج أكثر من عملية مقارنة سويًا. int a = 15; int b = 20; int c = 7; boolean result = a > b && a > c; وتستخدم && (كحرف العطف "و") للتعبير عن وجوب تحقق الشرطين معًا ليكون الناتج true ويكون false غير ذلك. boolean result = a > b || a > c; وتستخدم || (كحرف العطف "أو") للتعبير عن تحقق إحدى الشرطين أو تحققهما معًا ليكون الناتج true ويكون الناتج false عندما يكون الشرطين غير متحققين معًا. boolean result = !(a>b); وتعني ! عكس الناتج فإذا كان true يصبح false والعكس صحيح. التعليقات يحتاج المطوّر في بعض الأحيان لإضافة بعض التعليقات والملاحظات على البرنامج وذلك لتسهيل فهم ما كتبه من شيفرات عند قراءتها دون التأثير على الأوامر المكتوبة، حيث أن التعليقات لا يترجمها المترجم الخاص بجافا بل يهملها. تعليق السطر الواحد هذا النوع من التعليق يتم باستخدام علامتيّ //، ويجعل السطر المقابل لها تعليق لا يراه البرنامج. //This is a single-line comment int weekDays = 7; //Number of Days in a week كما ترى يقوم التعليق بتوضيح الأمور للمطوّر. تعليق الأسطر المتعددة يمكنك أن تكتب تعليق في عدة أسطر باستخدام /* */ لكتابة التعليق: /*This is a multi-line comment. That comment ends when it finds the closing marker. */ يتم حجز عدد من الأسطر بين */ و /* وتكون عبارة عن تعليق. ولن يتم تنفيذها في البرنامج، فوصول المترجم لـ */ تجعله يتجاهل كل ما يقابله حتى يصل لـ /* ثم يقوم بتنفيذ ما بعدها. لذا فالتعليقات في البرنامج تساهم في توضيحه وتجعل قراءته أسهل. فأي شيء يبدو واضحًا وبديهيًا عند كتابة البرنامج قد لا يبدو كذلك بعد مرور فترة طويلة. الجمل الشرطية وهي الجمل التي تنفذ عند تحقق شرط معين ولتنفيذها يتم استخدام if و if-else و switch، وإذا لم يتحقق هذا الشرط لا يتم تنفيذها. جملة if تعتبر جملة if من أبسط الجمل الشرطية فهي تحتوي على شرط عند تحققه يتم تنفيذ أوامر محددة ويتم تركيبها على الشكل التالي: if ( Condition ) { // Do Some Actions if it’s true } تُكتب كلمة if ويتم وضع الشرط بين الأقواس و عند تحقق الشرط يتم تنفيذ الأوامر المتواجدة بين القوسين { } وإذا لم يتحقق يتم تجاهل هذه الأوامر واستكمال الشفرة الخاصة بالبرنامج. مثال على ذلك: int x = 10; String result = “false”; if(x > 10){ result = “true”; } في المثال السابق يتم التحقق من قيمة المتغير x إذا كانت أكبر من الصفر أم لا، وفي هذه الحالة فالشرط سليم ويتم تخزين النص "true" داخل المتغير result، وإذا تم تغيير قيمة المتغير x إلى -5 مثلًا لن يتحقق الشرط وستظل قيمة النص "false". الجملة if-else وهي تقوم بنفس الوظيفة التي تقوم بها if عدا أنه إذا لم يتحقق الشرط الخاص بـ if تقوم بتنفيذ أوامر أخرى معرّفة لدى الجملة else، وبالتعديل على المثال السابق: int x = -6; String result ; if(x > 10){ result = “true”; }else{ result = “false”; } في المثال لا يتم تم وضع نص مبدئي في المتغير result ويتم التحقق بعد ذلك من الشرط الخاص بـ if إذا كان صحيحًا فسيتم وضع النص "true" داخل المتغير result أما إذا كان خاطئًا فسيتم وضع القيم "false" داخل المتغير result. ويمكن القيام بالتحقق بأكثر من شرط كما في المثال التالي: char grade = ‘B’; String result; if(grade==’A’){ result = “Excellent”; }else if(grade==’B’){ result = “Very good”; }else if(grade==’C’){ result = “good”; }else if(grade==’D’){ result = “passed”; }else{ result = “failed”; } في هذا المثال تم استخدام أكثر من شرط وجملة واحدة فقط التي تتحقق ويكون الشرط فيها صحيحًا وفي المثال فهي الجملة الثانية ويتم تخزين النص "very good". لاحظ أننا لا تستخدم == عند المقارنة بين النصوص من النوع String وتستخدم الدالة equals. جملة switch تستخدم هذه الجملة عندما نريد التحقق من قيمة متغير واحد فقط وتعتبر أكثر سهولة من if في هذه الحالة: switch(variable){ case 1: //Do something break; case 2: //Do something break; default: //Do something break; } وبتحويل المثال السابق الخاص بـ if باستخدام switch: char grade = ‘B’; String result; switch(grade){ case ‘A’: result = “Excellent”; break; case ‘B’: result = “Very good”; break; case ‘C’: result = “good”; break; case ‘D’: result = “passed”; break; default: result = “failed”; break; } ملاحظات يتم كتابة اسم المتغير فقط بين الأقواس الخاصة بـ switch ولا يتم تحديد شرط معين. تكتب كلمة case وتتبعها قيمة المتغير عند هذه الحالة حتى يتم تنفيذ الأوامر الخاصة بهذه الحالة إذا تساوت قيمة المتغير الخاص بـ switch مع القيمة الخاصة بـ case (في المثال السابق كان المتغير من النوع char لذا تم وضع القيم الخاصة بـ case بين علامتيّ التنصيص المفردة). في آخر كل حالة يتم وضع الأمر break وهو أمر للخروج من الجملة switch، وإذا لم يتم وضعه سيتم تنفيذ باقي الحالات المتواجدة داخل الجملة switch حتى نصل إلى الأمر break أو تنتهي الجملة switch. يتم تنفيذ الحالة default عندما يكون قيمة المتغير الخاص بـ switch لا يوجد لها حالة خاصة بها. جملة switch تتعامل مع المتغيرات من النوع int أو char أو String فقط. الجمل الشرطية التكرارية الجمل الشرطية التكرارية هي جمل تقوم بتنفيذ أوامر عدة مرات في حال كان الشرط صحيحًا، وتتشابه مع الجمل الشرطية في تركيبها وتختلف معها في عدد مرات تنفيذ الأمر. تمتلك لغة جافا عدة أنواع من الجمل التكرارية مثل while و do While و for. الجملة while وتتشابه تركيبة هذه الجملة مع الجملة if كالتالي: while (Condition){ //Do some Actions here } ويتم تنفيذ الأوامر داخل الجملة while طالما الشرط متحقق ويتم التوقف عندما يصبح الشرط خاطئًا، مثال على ذلك: int i = 0; int sum = 0; while( i < 5 ){ sum = sum + 1; i++; } في هذا المثال يكون الشرط صحيحًا فيتم تنفيذ الجمل داخل while ثم يتم التحقق من الشرط مرة أخرى ويكون صحيحًا وهكذا حتى يصبح الشرط خاطئًا ويُلاحظ أن الشرط لن يتحقق في حالة i تساوي 5 وعند الخروج من الجملة التكرارية تكون القيمة 5 مخزنة داخل المتغير sum. الجملة for وتختلف طريقة كتابة هذه الجملة عن الجملة while. for (initialization ; condition ; update){ // Do Some Actions here } داخل القوسين الخاصين بالجملة for يتم تقسيمها إلى ثلاث أقسام تفصلهم الفاصلة المنقوطة ";" وأول قسم يتم به تهيئة المتغير إعطائه قيمة ابتدائية، والقسم الثاني الشرط المعتاد، والقسم الأخير خاص بتحديث الشرط. فمثلًا لاستخدام for في المثال السابق الخاص بـ while: int sum =0; for(int i=0;i<5;i++){ sum = sum + 1; } ويقوم المثال السابق بنفس الوظيفة و ُلاحظ أنه تم دمج الجمل الثلاث التي كانت قبل جملة while والشرط الخاص بـ while والتحديث للشرط داخل جملة while في سطر واحد داخل الأقواس الخاصة بـ for. وتُستخدم الجمل التكرارية لتكرار تنفيذ أوامر محددة لحين غياب شرط معين يتم تحديده مسبقًا. سنواصل في الدرس القادم باقي أساسيات جافا التي تحتاج أن تعرفها قبل أن تشرع في برمجة تطبيقات أندرويد.