الحقول والتوابع والحالة
الحقول والتوابع والحالة
في الدرس السابق تعلّمت أن الصنف هو مخطط وأن الكائن هو شيء حقيقي يُبنى من ذلك المخطط. الآن حان الوقت للنظر داخل المخطط وفهم مكوّنيه الأهم: الحقول (ما يعرفه الكائن) والتوابع (ما يستطيع الكائن فعله). يمنح الحقول والتوابع معًا كل كائن حالته الخاصة وسلوكه المميز.
ما المقصود بالحالة؟
الحالة ببساطة هي مجموعة قيم البيانات التي يحتفظ بها الكائن في أي لحظة. تخيّل حسابًا بنكيًا: يمتلك دائمًا رصيدًا واسم مالك ورقم حساب. تلك هي حقوله، وقيمها الحالية تُشكّل حالته. كلّ حسابين كائنان منفصلان بحالتين منفصلتين — تغيير أحدهما لا يمسّ الآخر أبدًا.
حقول النسخة (Instance Fields)
الحقل المُعلَن مباشرةً داخل الصنف خارج أي تابع يُسمّى حقل نسخة. يحصل كل كائن على نسخته المستقلة من كل حقل نسخة.
لمشاهدة تلك النسخ المستقلة عمليًا، أنشئ كائنين وغيّر أحدهما:
alice وbob منطقتان مستقلتان في الذاكرة. الحقل balance موجود في كلتيهما، لكنهما متغيّران مختلفان تمامًا. هذه هي جوهر البرمجة الكائنية.
توابع النسخة (Instance Methods)
التابع هو كتلة كود مُسمّاة تنتمي إلى الصنف وتعمل على كائن محدد واحد. عند استدعاء تابع على كائن ما، تُمرّر Java الكائن نفسه إلى التابع بشكل خفي — وهذا ما يُعرف بـمرجع الكائن الضمني (ستتعرّف على صيغته الصريحة this في الدرس التالي؛ اعلم الآن فحسب أنه موجود).
الآن يضمّ الصنف البيانات والعمليات التي تنتمي إلى تلك البيانات:
مرجع الكائن الضمني
حين تكتب alice.deposit(500.0) يقوم Java بشيئين: يبحث عن التابع deposit في صنف BankAccount، ثم يُمرّر alice خفيةً كائنًا مستهدفًا. داخل deposit، كل اسم حقل مكشوف مثل balance هو اختصار لـbalance هذا الكائن. لهذا السبب ينتج عن استدعاء نفس التابع على كائنين مختلفين نتيجتان مختلفتان — كود التابع مشترك، لكنه يُنفَّذ في مواجهة حالة مختلفة في كل مرة.
void:
double amount = alice.getBalance(); يسترجع القيمة دون طباعتها، وهو أكثر فائدة للحسابات.
تطوّر الحالة عبر الزمن
الجمع بين الحقول والتوابع يعني أن حالة الكائن تتطوّر مع كل استدعاء تابع. هذا هو السلوك ذو الحالة — وهو ما يُميّز الكائنات عن هياكل البيانات البسيطة. تخيّل استدعاء deposit عشر مرات: ينمو balance عشر مرات، غير أن كائن الحساب يبقى نفس الكائن في الذاكرة بنفس المرجع.
الحقول مقابل المتغيّرات المحلية
كثيرًا ما يخلط المبتدئون بين حقول النسخة والمتغيّرات المحلية. إليك الفروق الأساسية:
- حقول النسخة تُعلَن داخل الصنف خارج كل التوابع. تعيش طالما يعيش الكائن وتحتفظ بالحالة بين استدعاءات التوابع.
- المتغيّرات المحلية تُعلَن داخل تابع. توجد فقط طوال مدة ذلك الاستدعاء وتختفي فور انتهاء التابع.
0، والمنطقية بـfalse، والكائنات بـnull. الاعتماد الصامت على تلك القيم الافتراضية قد يتسبّب لاحقًا في NullPointerException. اجعل القيم الابتدائية صريحة قدر الإمكان.
الخلاصة
تخزّن حقول النسخة حالة الكائن — يحصل كل كائن على نسخته المستقلة. تعمل توابع النسخة على تلك الحالة؛ عند استدعائها تتلقّى مرجعًا ضمنيًا إلى الكائن المحدد الذي تعمل عليه. تحوّل الحقول والتوابع معًا الصنف من حاوية بيانات سلبية إلى كيان فعّال مكتفٍ بذاته. في الدرس التالي ستتعلّم كيف تتيح لك الدوال البانية (constructors) إعداد تلك الحالة الابتدائية لحظة إنشاء الكائن.