التغليف Encapsulation و private و getters و setters
لماذا نخفي البيانات؟ وما معنى private؟ وكيف نستخدم Getters و Setters لحماية كائناتنا من القيم الخاطئة؟
المشكلة — لماذا نحتاج Encapsulation؟
في الدروس السابقة جعلنا خصائص الكلاس مفتوحة — أي جزء من البرنامج يستطيع تعديلها مباشرة:
class Person { String name; int age; } Person p1 = new Person(); p1.age = -100; ← عمر سالب! Java لن تمنعه p1.name = ""; ← اسم فارغ! لا أحد يمنعه
بدون Encapsulation
أي مكان في البرنامج يستطيع وضع قيم خاطئة — عمر سالب، اسم فارغ، راتب سالب...
مع Encapsulation
البيانات محمية — لا يمكن تعديلها إلا بطرق محددة نكتبها نحن مع شروط التحقق.
ما هو Encapsulation؟
التغليف (Encapsulation) هو أحد أعمدة البرمجة الكائنية — ويعني ببساطة: إخفاء البيانات داخل الكلاس والسماح بالوصول إليها فقط بطرق منظّمة.
private
إخفاء الخاصية
تجعل الخاصية مرئية داخل الكلاس فقط — لا يمكن لأي كود خارج الكلاس الوصول إليها مباشرة.
getter
دالة القراءة
دالة تُرجع قيمة الخاصية للقراءة — مثل getName() و getAge().
setter
دالة التعديل
دالة تُعدّل قيمة الخاصية — يمكن فيها وضع شروط تحقق تمنع القيم الخاطئة.
مثال كامل — Person بطريقة احترافية
سنحوّل الكلاس القديم لكلاس محمي بالكامل مع Getters و Setters:
class Person { // ① الخصائص private — مخفية عن الخارج private String name; private int age; // ② Getter للاسم — قراءة فقط public String getName() { return name; } // ③ Setter للاسم — مع تحقق public void setName(String name) { if (name != null && !name.isEmpty()) { this.name = name; } } // ④ Getter للعمر public int getAge() { return age; } // ⑤ Setter للعمر — يمنع القيم السالبة public void setAge(int age) { if (age >= 0) { this.age = age; } } }
إخفاء الخصائص
لا يمكن لأي كود خارج الكلاس الوصول لـ name و age مباشرة.
Getter — دالة قراءة
ترجع قيمة name للخارج بشكل آمن بدون السماح بتعديلها.
Setter — دالة تعديل مع تحقق
يتحقق أن الاسم ليس null وليس فارغاً قبل الحفظ — يرفض الاسم الفارغ صامتاً.
Setter — يمنع العمر السالب
الشرط age >= 0 يضمن أن العمر لن يكون سالباً أبداً.
كيف نستخدم الكلاس المُغلَّف؟
بعد التغليف، تغيّرت طريقة التعامل مع الكائن:
❌ لم يعد مسموحاً
Person p = new Person(); // هذا سيعطي خطأ في التجميع! p.age = -100; p.name = "";
✅ الطريقة الصحيحة
Person p = new Person(); p.setName("Ahmed"); p.setAge(25);
Person p = new Person(); // تعديل عبر Setters p.setName("Ahmed"); p.setAge(25); // قراءة عبر Getters System.out.println(p.getName()); ← Ahmed System.out.println(p.getAge()); ← 25 // محاولة قيمة خاطئة — ستُتجاهل بهدوء p.setAge(-50); System.out.println(p.getAge()); ← 25 (لم يتغير)
Ahmed 25 25
لاحظ أن setAge(-50) لم يُنفّذ لأن الشرط age >= 0 فشل — العمر بقي 25. هذا هو التغليف في العمل!
اتفاقية التسمية — كيف نسمي Getters و Setters؟
في Java يوجد اتفاقية (Convention) لتسمية Getters و Setters — يجب اتباعها لأن أدوات Java تعتمد عليها:
| الخاصية | Getter (قراءة) | Setter (تعديل) |
|---|---|---|
name |
getName() |
setName(String name) |
age |
getAge() |
setAge(int age) |
salary |
getSalary() |
setSalary(double salary) |
isActive |
isActive() |
setActive(boolean val) |
للخصائص من نوع boolean، الـ Getter يبدأ بـ is بدل get — مثل isActive() بدل getActive().
لماذا Encapsulation مهم في البرمجة الحقيقية؟
حماية البيانات من القيم الخاطئة
الـ Setter يمنع إدخال عمر سالب، راتب صفر، تاريخ غير منطقي — مما يجعل برنامجك أكثر موثوقية وأماناً.
سهولة الصيانة والتعديل
تغيير قاعدة التحقق يتم في مكان واحد (الـ Setter) فقط — دون تعديل كل الكود الذي يستخدم هذا الكلاس.
فصل المسؤوليات
الكلاس مسؤول عن بياناته — أي كود آخر يستخدمه بدون معرفة التفاصيل الداخلية. هذا هو مبدأ التغليف.
إضافة منطق بدون تغيير الواجهة
يمكنك لاحقاً إضافة تحقق معقد في الـ Setter (مثل التحقق من قاعدة البيانات) دون أن يتأثر الكود الخارجي بشيء.
أخطاء شائعة عند المبتدئين ⚠️
نسيان كتابة Getter/Setter ثم التساؤل لماذا لا يعمل
❌ الخطأ
private String name;
// نسي كتابة getName() و setName()
p.name = "Ahmed"; // خطأ تجميع
p.getName(); // خطأ — الدالة غير موجودة
Setter بدون أي تحقق — يفقد فائدة التغليف
❌ لا فائدة منه
void setAge(int age) {
this.age = age;
}
يقبل -100 و -999!
✅ مع تحقق
void setAge(int age) {
if (age >= 0)
this.age = age;
}
الخلط بين get و set
getName()
قراءة — ترجع String
setName(String n)
تعديل — تأخذ مدخلاً
📋 ملخص الدرس
private تخفي الخاصية — لا يصل لها أحد من الخارج
Getter = دالة قراءة ترجع القيمة
Setter = دالة تعديل مع شروط تحقق
التسمية: getName() و setName()
🎉 أنجزت أساسيات OOP!
الآن لديك أساس قوي في البرمجة الكائنية: Class ← Object ← Constructor ← Encapsulation.
⏭️ في الدروس القادمة:
سنتعلم الثوابت (final)، الكلمة المحجوزة static، المصفوفات، ثم مشروع صغير لتجميع ما تعلمته. 🚀