إخفاء التفويض (Hide Delegate)
المشكلة
وجود حقلٍ (field) مٌخصَّص للبيانات في صنفٍ (class) ما (أو في عددٍ من الأصناف)، ولهذا الحقل بياناته وسلوكه (behaviour) المرتبط به.
الحل
إنشاء صنفٍ جديدٍ ليُوضَع فيه الحقل (field) بالإضافة إلى سلوكه المرتبط به، وتخزين كائنٍ (object) من هذا الصنف الجديد في الصنف الأصليّ للحقل.
مثال
قبل إعادة التصميم
يحتوي الصنف Order
على الحقل customer
الذي يحتوي بيانات نصيّة (من النوع String
) كما هو واضح في مخطط الأصناف الآتي:
بعد إعادة التصميم
أصبح هنالك صنفٌ جديدٍ باسم Customer
لتخزين بيانات الحقل السابق (الحقل customer
) باسم name
ويرتبط الصنفان بعلاقة has a (أي بمجرد وجود كائن Order
فلا بد من وجود كائن Customer
له)، فيصبح المخطط بالشكل:
لم إعادة التصميم؟
تُعَدُّ هذه التقنية حالةً خاصة من تقنية استخراج الصنف (Extract Class) وتختلفان بالسبب وراء إعادة التصميم (refactoring)؛ ففي استخراج الصنف هنالك صنفٌ وحيدٌ مسؤولٌ عن عدّة مهامٍ تُوزَّع عبر إعادة التصميم على الأصناف الأخرى، أما في حالة تحويل قيم البيانات إلى كائنٍ (object) من صنفٍ جديدٍ فهنالك حقلٌ أساسيّ (primitive field) يحتوي على بيانات عدديّة أو نصيّة أو …إلخ. ولم يعد التعامل معه أمرًا بسيطًا بسبب تطوير البرنامج وازدياد تعقيده، إذ أصبح لهذا الحقل بياناته وسلوكه المرتبط به، كما وقد تتكرَّر هذه المجموعة من «الحقل وارتباطاته» في عدّة أصنافٍ أخرى وبإعادة التصميم ستحدُّ من تكرار الشيفرة بلا جدوى، وبهذا يكون من الأفضل إفرادُ حقل البيانات (مع كافّة ما يرتبط به) في صنفٍ خاصٍّ به وإنشاء كائنٍ ينوب عنه في صنفه الأصليّ.
فوائد تطبيق الحل
تحسين الارتباط (relatedness) داخل الأصناف، إذ تُوضَع البيانات في صنفٍ واحدٍ مع كلِّ ما يتعلَّق بها من عمليات.
آلية الحل
قبل البدء بأيّة خطوة من خطوات الحل يجب التأكُّد أولًا من عدم وجود مرجعيّات مباشرة (direct references) لهذا الحقل (field) من داخل الصنف (class) ذاته، فإن وُجِدت فيكمن الحل بتقنية التغليف الداخليّ للحقل (Self Field Encapsulation) لإخفائه في الصنف الأصليّ، وإن لم يكن كذلك فخطوات تقنية الحل الحاليّة هي:
- إنشاء صنفٍ جديدٍ ونسخ الحقل وتابع وصوله
getter
إليه، ثمَّ إنشاء بانٍ (constructor) يقبل قيمة هذا الحقل كمعاملٍ (parameter) له، ويجب ألّا يحتوي الصنف على تابعsetter
لأنّ ذلك يعني إنشاء كائنٍ بالقيمة الجديدة كلما استُدعي التابع من الصنف الأصليّ. - تغيير نوع الحقل (field type) في الصنف الأصليّ ليصبح من نوع الصنف الجديد.
- استدعاء التابع
getter
للكائن (object) المعبِّر عن الحقل من داخل التابعgetter
في الصنف الأصليّ. - إنشاء كائنٍ بالقيمة الجديدة داخل التابع
setter
، وقد تحتاج إلى إنشاء كائنٍ جديدٍ أيضًا في الباني (constructor) إن كان هنالك قيمٌ أوليّة (initial values) تُسند إلى الحقل سابقًا.
ما الخطوة التالية؟
يُستحسَن تطبيق تقنية الحل بتغيير القيمة إلى مرجعيّة (Change Value to Reference) على الحقل الذي يحتوي الكائن من بعد تطبيق تقنية الحل السابقة، وذلك لضمان وجود مرجعيّةٍ إلى كائنٍ واحدٍ فقط متناسبٍ مع القيمة بدلًا من تحزين العشرات من الكائنات لحفظ قيمة واحدة! وغالبًا ما تُستخدَم هذه التقنية للحصول على كائنٍ برمجيٍّ واحدٍ يقابل كلَّ كائنٍ على أرض الواقع (مستخدِمٍ أو طلبٍ أو مستندٍ أو ...إلخ.)، ولن تكون هذه التقنية نافعةً للكائنات مثل التاريخ (date) أو العملة (money) أو المجالات (ranges) أو ...إلخ.