الكائنات غير المتقلبة و الكائنات المتقلبة والنسخة الدفاعية

الكائنات غير المتقلبة Immutable objects و الكائنات المتقلبة mutable objects والنسخة الدفاعية Defensive copying

تنقسم الكائنات على حسب حالتها وقابلية خصاصها للتغيير إلى نوعين
1- كائنات متقلبة
2- كائنات غير متقلبة
الكائنات المتقلبة هي عبارة عن كائنات تتغير الخصائص -المتغيرات الموجودة في نطاق الفئة Field Variables- التابعة لها باستمرار
الكائنات غير المتقلبة و هي التي تحصل على خصائصها مرة واحدة فلا تتغير بعدها مطلقاً
تحصل خصائص هذه الكائنات على قيمها عن طريق صانع الكائنات constractor فقط

مثال على الكائنات المتقلبة الإنسان تتغير خصائصه عبر الزمن فقد يكون مبصراً اليوم ثم يصير أعمى أو العكس
مثال على الكائنات غير المتقلبة الكلمة فعندما تقول أن الكائن كلمة يحتوي على كلمة إنسان نجد أنها ثابتة لا تتغير لها عدد الحروف نفسه ولها الهجاء نفسه
مثال في الجافا على كائنات غير متقلبة String , Integer
الكائنات غير المتقلبة مستقرة بعيدة كل البعد عن مشاكل المؤشرات pointer و الذاكرة memory ومشاكل التعديل على قيمة المتغيرات -التزامن synchronization-
و في مايلي تفصيل ذلك

فوائد الثبوتية immutability في الكائنات

1- الحرية في التخزين
بمعنى آخر أنك لا تحتاج إلى تغيير النسخة الاحتياطية عندك لكائن غير متقلب السبب أنه ثابت الخواص
لذلك أنت تستطيع تخزين نسخة من متغيراته أو من الدوال التابعة له
بينما لابد من الاحتياط في التعامل مع الكائنات المتقلبة لأنها تتغير باستمرار
مثلاُ عندما تتعامل مع كائن من نوع إنسان باستمرار فيجب عليك في كل مرة أن تتأكد من أنه لم يصب بالعمى
لكن عندما تتعامل مع كائن من نوع كلمة فأنتا بالتأكيد ستتعامل مع أي نسخة منه فكل النسخ تقوم بنفس المهمة وتحتوي نفس الكلمة
تعالوا معي ننظر إلى هذه الشفرة على فرض أن task1 عبارة عن كائن متقلب

public class Test{public static void main (String args[]){
Date d = new Date();
// هناك حلين أمام الدالة مجدولة المهام لكي تتعامل

// مع المهمة هذه المهمة تابع قراءة المقال لتعرفهما
Scheduler.scheduleTask(task1, d);

}

}

نلاحظ في المثال السابق أن الدالة scheduleTask لديها حل من اثنين
أن تقوم بالتعديل على task1 مباشرة وهو سيئ بشكل كبير لأنك لو أردت تنفيذ هذه المهمة مرة أخرى فستجد شيء آخر مختلف عن المهمة الأصلية
أن تقوم ببناء كائن جديد وهو مايسمى بالنسخة الدفاعية defensively copy تقوم بمنع التعديل على خصائص task1
بينما لو كنا نتحدث عن كائنات غير متقلبة فلا مشاكل هنا لأنها تلقائياً تقوم بإنتاج النسخة الدفاعية في حال الحاجة لها
2- الإعفاء من عملية التزامن synchronization بين الكائنات
بالنسبة للكائنات المتقلبة تعاني وبشدة من تعددية القراءة والكتابة على الكائن في نفس الوقت
فهناك مشكلتين أساسيتان تواجهما هذه الكائنات:
أ- تعددية الكتاب :أكثر من thread يقوم بالكتابة على الكائن في نفس الوقت
ب- تعددية الكتاب والقراء :كاتب أو أكثر و قارئ أو أكثر يقومون بالكتابة والقراءة في نفس الوقت
هذه المشاكل قد تؤدي إلى كارثة بالنسبة لخصائص الكائن
الحل لهذه المشاكل هو التزامن طبعاً له عيوب كثيرة منها الإبطاء في عملية التشغيل ومنها التكلفة العالية للإنشاء
هذه المشاكل كلها لا يعاني منها الكائن الغير متقلب
3- الحماية من الدوال ذات السلوك المريض
ويقصد بذات السلوك المريض أنها تتعدى على الكائنات التي تتعامل معها بتغيير خصائصها وهو شيء غير مرغوب في الغالب
في حال وجود دالة تقوم بتعديل على الكائن فإن الكائن المتقلب يستجيب بسهولة لها مما يغير محتواه
قد يحصل شيء من هذا بدون قصد طبعاً فيصعب على المبرمج معرفة مكان المشكلة
أما بالنسبة للكائنات غير المتقلبة فهي من الذكاء بمكان حيث لن تقوم بالتعديل على نفسها
وإنما تقوم بعمل نسخة دفاعية وتجعل هذه الدالة تغير عليها

النسخة الدفاعية وأهميتها

النسخة الاحتياطية وهي نسخة تقوم بعملها من الكائن لكي تبعده عن التعديلات الغير شرعية التي قد تقوم بها دوال مريضة
الكائنات المتقلبة تقوم بعمل نسخة دفاعية من الكائنات التي يأخذها صانع الكائنات الخاص بها لكي تضمن عدم تأثر الكائنات التي تملكها بأي شيء قبل تكوين الكائن – مؤشرات قديمة تقوم بعمليات تعديل على الكائن الممرر للكائن المتقلب-
وهي تقوم بحماية كائناتها بنسخة دفاعية ترجعها لمن يريد معرفتها بدلاً من إرسال مؤشر للكائن مباشرة
فمثلاً عندما يطلب شخص الحرف الأول من كلمة إنسان فإنها لا ترجع مؤشر مباشر له وإنما تقومبنسخ الحرف إلى مكان آخر وإرسالة النسخة الجديدة

كيف تقوم بكتابة فئة غير متقلبة Immutable Class؟؟

لكي تقوم بكتابة فئة غير متقلبة يجب عليك الإلتزام بالتالي:
1- في البداية اجعل كل المتغيرات العامة private
2- أي متغير يشير إلى كائنات متقلبة فيجب أن يكون :
أ- يشير إلى الكائنات التي تشير إليه فقط بدون تغيير بعد أن يتم إنشاء الكائن غير المتقلب
ب- لا تتغير حالة المؤشرات للكائنات التابعة له
3- لا تضع أي دالة تقوم بالتعديل على المتغيرات العامة Field للفئة
4- لا تستخدم الكائنات المررة مباشرة من صانع الكائنات وإنما قم باستخدام نسخة منها بالتالي لا تستخدم أداة الإشارة this أبداً
5- في حالة وجود الدوال المعطية getSomething فلا تعطي المتغير نفسه ولكن أعطي نسخة منه

مثال على فئة غير متقلبة

class ImmutableArrayHolder {private int[] theArray;
// الطريقة الصحيحة لأخذ المصفوفة هي نسخها

public ImmutableArrayHolder(int[] anArray) {

this.theArray = (int[]) anArray.clone();

}

// الطريقة الخاطئة لأخذ المصفوفة هي نسخ المؤشر الخاص بها

// لأن المؤشرات القديمة موجودة ومتاحة ويمكن من خلالها التعديل على المصفوفة

/*public ImmutableArrayHolder(int[] anArray) {

this.theArray = anArray;

}*/

// الطريقة الصحيحة لعمل الدوال المساعدة عدم إرجاع مؤشر لها

public int getArrayLength() { return theArray.length }

public int getArray(int n) { return theArray[n]; }

// الطريقة الصحيحة لعمل دوال ترجع المصفوفة عن طريق clone()

public int[] getArray() { return (int[]) theArray.clone(); }

// الطريقة الخاطئة لارجاع المصفوفة عن طريق مؤشر

// لها لأن هذا قد يؤدي إلى تعديل على المصفوفة

/*public int[] getArray() { return theArray }*/

}

قمت في المثال السابق بوضع بعض الدوال وصانع كائنات التي يمكنك استخدامها بدون أية مشاكل
كما وضعت بعض الأمثلة التي تسبب مشاكل
ملاحظة: هناك شبه واضع بين المتغيرات النهائية (ثابت) وبين الكائنات غير المتقلبة
للاسفتسار عن أي شيء في المقالة السابقة يمكن التعليق هنا أو مراسلتي على بريدي
المراجع مرتبة على حسب الأهمية:
1- مقال بعنوان Java theory and practice: To mutate or not to mutate?
http://www.ibm.com/developerworks/java/library/j-jtp02183.html
2- مقال للأخ مبتدئ جافا في الفريق العربي للبرمجة
http://www.arabteam2000-forum.com/index.php?showtopic=131865
3- مقال بعنوان Immutable objects
http://www.javapractices.com/Topic29.cjp
في النهاية أحب أن أنوه على أن هذا المقال لم يترجم حرفياً من المراجع السابقة
وإنما كان نتاج إطلاع على الموضوع من عدة مقالات عربية وأجنبية في النهاية وجدت أنني
أستسقي غالب أفكاري من هذه المقالات فلم أحب أن أنسب لنفسي ما لم تقم به
المترجم:علاء الصالحي
البريد:alaadiaa1@hotmail.com

سبحانك اللهم وبحمدك واستغفرك اللهم وأتوب إليك

5 Responses to “الكائنات غير المتقلبة و الكائنات المتقلبة والنسخة الدفاعية”

  1. aaaa قال:

    جميل جداً اخ علاء
    مشكور ونطلب المزيد من خبراتك البرمجية
    استمر

  2. admin قال:

    شكراً لك أخ aaaa على مرورك الكريم

  3. nvgmr قال:

    HELLO, VERY NICE ARTICLE.
    Thanks

  4. yxxem قال:

    Good Job. Good LUCK!
    Thanks

  5. admin قال:

    Thank You
    for your attention
    Eng.Alaa Alsalhi

Leave a Reply