Refactoring/introduce local extension
المشكلة
الحاجة إلى بعض التوابع (methods) غير الموجودة في الصنف المساعد (utility class)، ومن غير الممكن إضافتها إلى ذلك الصنف.
الحل
إنشاء صنفٍ (class) جديدٍ يحتوي التوابع اللازمة، وجعله كصنف تغليفٍ (wrapper) للصنف المساعد أو كصنفٍ فرعيٍّ (subclass) له.
مثال
قبل إعادة التصميم
يعتمد صنف العميل (ClientClass) على الصنف المساعد Date ولكنّه بحاجة إلى بعض التوابع غير الموجودة فيه (كتابع الحصول على اليوم التالي مثلًا):
بعد إعادة التصميم
أصبح هنالك صنف جديد باسم MfDate
يُعَدُّ صنفًا (subclass) فرعيًا للصنف المساعد Date
يحتوي التوابع اللازمة، كما في المخطط:
لم إعادة التصميم؟
ما الأسوء من أن تحتاج تابعًا في الصنف فلا تجده؟! ألا تستطيع إضافته! (بسبب وجوده في مكتبةٍ لا تملك صلاحية التعديل على مكوناتها مثلًا)، وإليك الحل:
- إنشاء صنفٍ فرعيّ (subclass) من الصنف المساعد، يحتوي على التوابع التي تحتاجها من بعد أن يرِث (inherit) كافّة التوابع والحقول (fields) الأخرى من صنفه الأعلى (وهو الصنف المساعد الأساسيّ)، وهذه الطريقة من أسهل الطرق إلا أنّها قد تصبح مستحيلةً بوجود المعامل
final
للصنف المساعد ممّا يمنع الوراثة منه. - إنشاء صنف تغليفٍ (wrapper class) يحتوي على كافّة التوابع اللازمة وينتقل (delegate) عند الضرورة إلى الكائن المأخوذ من الصنف المساعد (utility class object)، وهذه الطريقة أصعب قليلًا بسبب الحاجة إلى شيفرةٍ للربط ما بين صنف التغليف وكائن الصنف المساعد (utility class object)، بالإضافة إلى عددٍ كبيرٍ من التوابع لتوفير الانتقال (delegation)، والتي تُعَدُّ بمثابة واجهةٍ عامةٍ (public interface) للصنف المساعد.
فوائد تطبيق الحل
التقليل من الشيفرة الموجودة في صنف العميل (client class)، والتي قد لا تتعلَّق أصلًا بمهامه الفعليّة (هدفها فقط الحصول على ما لا يحتويه الصنف المساعد)، وبإضافة صنفٍ جديدٍ (إما صنف تغليفٍ أو صنف فرعيّ) لاحتواء تلك التوابع ستصبح مكوِّنات البرنامج أكثر ترابطًا ومتاحةً لإعادة الاستخدام المتكرِّر (reusability).
آلية الحل
- إنشاء صنفٍ إضافيٍّ وبهذا تكون أمام خيارين: الأول: جعله صنفًا فرعيًا للصنف المساعد (utility class) بإنشاء علاقة وراثة (inheritance). الثاني: جعله صنف تغليفٍ ولا بُدَّ حينها من تخصيص حقلٍ (field) فيه لتخزين كائن الصنف المساعد الذي سيكون الانتقال (delegation) إليه، وستحتاج كذلك إلى إضافة توابع عامّة (public methods) تتوافق مع التوابع الأساسية في الصنف المساعد، يحتوي كلٌّ منها على انتقال (delegation) إلى التابع الأصلي المماثل له في كائن الصنف المساعد.
- إنشاء بانٍ (constructor) لهذا الصنف يستخدم نفس معاملات (parameters) الباني الأساسيِّ للصنف المساعد (utility class).
- إنشاء بانٍ بديل يقبل معاملًا واحدًا فقط وهو كائن الصنف الأساسيّ، وهذا سيساعد على تعويض الصنف الأصليّ بكائن إضافي (extension).
- إنشاء توابع إضافيّة (extension methods) في الصنف، ونقل كافة التوابع الدخيلة (foreign methods) من الأصناف الأخرى إلى هذا الصنف، أو من الممكن حذف التوابع الدخيلة إن كانت تكرِّر مهامًا موجودةً في التوابع الإضافيّة.
- تبديل استخدام الصنف المساعد إلى استخدام الصنف الإضافي في كل موضعٍ يحتاجه.