الفرق بين المراجعتين ل"Refactoring/extract class"

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث
ط (تعديل حجم الصور.)
(مراجعة وتدقيق.)
 
سطر 10: سطر 10:
 
==== قبل إعادة التصميم ====
 
==== قبل إعادة التصميم ====
 
يحتوي الصنف <code>Person</code> على عددٍ من الحقول كاسم الشخص (name) ورمز منطقة المكتب (officeAreaCode) ورقمه (officeNumber)، وتابعًا للحصول على هذا الرقم باسم <code>getTelephoneNumber</code>، كما في مخطط الأصناف الآتي:
 
يحتوي الصنف <code>Person</code> على عددٍ من الحقول كاسم الشخص (name) ورمز منطقة المكتب (officeAreaCode) ورقمه (officeNumber)، وتابعًا للحصول على هذا الرقم باسم <code>getTelephoneNumber</code>، كما في مخطط الأصناف الآتي:
[[ملف:Extract-Class-Before.png|بديل=الصنف Person يحتوي على عددٍ من الحقول كاسم الشخص (name) ورمز منطقة المكتب (officeAreaCode) ورقمه (officeNumber)، وتابعًا للحصول على هذا الرقم باسم getTelephoneNumber.|بدون|إطار|الصنف Person يحتوي على عددٍ من الحقول كاسم الشخص (name) ورمز منطقة المكتب (officeAreaCode) ورقمه (officeNumber)، وتابعًا للحصول على هذا الرقم باسم getTelephoneNumber.|219x219بك]]
+
[[ملف:Extract-Class-Before.png|بديل=الصنف Person يحتوي على عددٍ من الحقول كاسم الشخص (name) ورمز منطقة المكتب (officeAreaCode) ورقمه (officeNumber)، وتابعًا للحصول على هذا الرقم باسم getTelephoneNumber.|بدون|الصنف Person يحتوي على عددٍ من الحقول كاسم الشخص (name) ورمز منطقة المكتب (officeAreaCode) ورقمه (officeNumber)، وتابعًا للحصول على هذا الرقم باسم getTelephoneNumber.|313x313px|تصغير]]
  
 
==== بعد إعادة التصميم ====
 
==== بعد إعادة التصميم ====
 
أصبح هنالك صنفٌ مخصَّصٌ للرقم الهاتفي (TelephoneNumber) يشمل كلَّ الحقول والتوابع المتعلقة به، وبقي الصنف الأصليّ <code>Person</code> محتويًا على ما تبقى من الحقول والتوابع، أي يصبح الصنفان بالشكل:
 
أصبح هنالك صنفٌ مخصَّصٌ للرقم الهاتفي (TelephoneNumber) يشمل كلَّ الحقول والتوابع المتعلقة به، وبقي الصنف الأصليّ <code>Person</code> محتويًا على ما تبقى من الحقول والتوابع، أي يصبح الصنفان بالشكل:
[[ملف:Extract-Class-After.png|بديل=الصنف Person يحتوي على حقلٍ واحدٍ باسم name وتابعٍٍ للحصول على رقم الهاتف getTelephoneNumber، أمّا الصنف TelephoneNumber فهو يحتوي على حقلين باسم officeAreaCode و officeNumber بالإضافة إلى التابع السابق getTelephoneNumber.|بدون|إطار|الصنف Person يحتوي على حقلٍ واحدٍ باسم name وتابعٍٍ للحصول على رقم الهاتف getTelephoneNumber، أمّا الصنف TelephoneNumber فهو يحتوي على حقلين باسم officeAreaCode و officeNumber بالإضافة إلى التابع السابق getTelephoneNumber.|609x609بك]]
+
[[ملف:Extract-Class-After.png|بديل=الصنف Person يحتوي على حقلٍ واحدٍ باسم name وتابعٍٍ للحصول على رقم الهاتف getTelephoneNumber، أمّا الصنف TelephoneNumber فهو يحتوي على حقلين باسم officeAreaCode و officeNumber بالإضافة إلى التابع السابق getTelephoneNumber.|بدون|الصنف Person يحتوي على حقلٍ واحدٍ باسم name وتابعٍٍ للحصول على رقم الهاتف getTelephoneNumber، أمّا الصنف TelephoneNumber فهو يحتوي على حقلين باسم officeAreaCode و officeNumber بالإضافة إلى التابع السابق getTelephoneNumber.|500x500px|تصغير]]
  
 
== لم إعادة التصميم؟ ==
 
== لم إعادة التصميم؟ ==
سطر 24: سطر 24:
  
 
== مساوئ تطبيق الحل ==
 
== مساوئ تطبيق الحل ==
عند التطبيق المفرط لهذه التقنية ستحصل على عددٍ كبيرٍ من الأصناف ولا بُدَّ حينئذٍ من اللجوء إلى تضمين الصنف (Inline Class).
+
عند التطبيق المفرط لهذه التقنية ستحصل على عددٍ كبيرٍ من الأصناف ولا بُدَّ حينئذٍ من اللجوء إلى [[Refactoring/inline class|تضمين الصنف]] (Inline Class).
  
 
== آلية الحل ==
 
== آلية الحل ==
سطر 30: سطر 30:
 
# إنشاء صنفٍ جديد لاحتواء المهمة التي يُرغب بفصلها عن الصنف الحاليّ.
 
# إنشاء صنفٍ جديد لاحتواء المهمة التي يُرغب بفصلها عن الصنف الحاليّ.
 
# ربط الصنفين بعلاقةٍ أحاديّة الاتجاه (unidirectional) وذلك لإتاحة استخدام الصنف الجديد دون مشاكل تُذكَر، أمّا إن كان من الضروري الربط ما بين الصنفين بعلاقة ثنائيّة الاتجاه (bidirectional) فلا مشكلة في ذلك مؤقتًا.
 
# ربط الصنفين بعلاقةٍ أحاديّة الاتجاه (unidirectional) وذلك لإتاحة استخدام الصنف الجديد دون مشاكل تُذكَر، أمّا إن كان من الضروري الربط ما بين الصنفين بعلاقة ثنائيّة الاتجاه (bidirectional) فلا مشكلة في ذلك مؤقتًا.
# الاستفادة من تقنيتي نقل الحقول (Move Fields) ونقل التوابع (Move Methods) لنقل الحقول والتوابع المرتبطة بمهمة الصنف الجديد إليه، ومن الأفضل -بالنسبة للتوابع- البدءُ بنقل التوابع الخاصّة (private) للتقليل من احتمال حدوث الأخطاء، ويكون النقل عبر خطواتٍ صغيرةٍ مع ضرورة اختبار النتائج بعد كلِّ عملية نقلٍ لتجنُّب الوقوع بوابلٍ من الأخطاء المتشابكة وتعذُّر حلها في النهاية!  وبعد الانتهاء من النقل بأكمله، عليك بإلقاء نظرةٍ شاملةٍ على الأصناف الناتجة، فمن الممكن أن تُعيد تسمية الصنف الأصليّ لتصبح أكثر وضوحًا، وتتأكَّد من إمكانيّة التخلص من علاقة الربط ثنائيّة الاتجاه ما بين الصنفين في حال وجودها.
+
# الاستفادة من تقنيتي [[Refactoring/move field|نقل الحقول]] (Move Fields) و<nowiki/>[[Refactoring/move method|نقل التوابع]] (Move Methods) لنقل الحقول والتوابع المرتبطة بمهمة الصنف الجديد إليه، ومن الأفضل -بالنسبة للتوابع- البدءُ بنقل التوابع الخاصّة (private) للتقليل من احتمال حدوث الأخطاء، ويكون النقل عبر خطواتٍ صغيرةٍ مع ضرورة اختبار النتائج بعد كلِّ عملية نقلٍ لتجنُّب الوقوع بوابلٍ من الأخطاء المتشابكة وتعذُّر حلها في النهاية!  وبعد الانتهاء من النقل بأكمله، عليك بإلقاء نظرةٍ شاملةٍ على الأصناف الناتجة، فمن الممكن أن تُعيد تسمية الصنف الأصليّ لتصبح أكثر وضوحًا، وتتأكَّد من إمكانيّة التخلص من علاقة الربط ثنائيّة الاتجاه ما بين الصنفين في حال وجودها.
 
# ضمان الوصول إلى الصنف الجديد من خارجه، إذ من الممكن إخفاء الصنف كليًا عن العميل بجعله خاصًّا (private) وإدارته عبر الحقول المتبقية في الصنف السابق (الصنف الأصلي)، أو من الممكن جعله عامًّا (public) وإعطاء العميل إمكانيّة تغيير القيم مباشرةً. يعتمد قرار تحديد الوصول إليه (عامًا أو خاصًّا) على مستوى الأمان المطلوب للصنف الأصليّ عند حدوث بعض التغييرات غير المتوقَّعة في قيم الصنف الجديد.
 
# ضمان الوصول إلى الصنف الجديد من خارجه، إذ من الممكن إخفاء الصنف كليًا عن العميل بجعله خاصًّا (private) وإدارته عبر الحقول المتبقية في الصنف السابق (الصنف الأصلي)، أو من الممكن جعله عامًّا (public) وإعطاء العميل إمكانيّة تغيير القيم مباشرةً. يعتمد قرار تحديد الوصول إليه (عامًا أو خاصًّا) على مستوى الأمان المطلوب للصنف الأصليّ عند حدوث بعض التغييرات غير المتوقَّعة في قيم الصنف الجديد.
  
سطر 41: سطر 41:
 
* [https://refactoring.guru/extract-class صفحة توثيق استخراج الصنف في موقع refactoring.guru.]
 
* [https://refactoring.guru/extract-class صفحة توثيق استخراج الصنف في موقع refactoring.guru.]
 
[[تصنيف:Refactoring]]
 
[[تصنيف:Refactoring]]
 +
[[تصنيف:Refactoring Techniques]]
 +
[[تصنيف:Refactoring Moving Features between Objects]]

المراجعة الحالية بتاريخ 09:09، 2 مارس 2019

المشكلة

وجود صنفٍ (class) واحدٍ يقوم بمهامٍ عديدةٍ يمكن توزيعها على صنفين.

الحل

إنشاء صنفٍ جديدٍ ونقل بعض الحقول (fields) والتوابع (methods) إليه، والتي تتعلَّق بالمهام الوظيفيّة (functionality) لهذا الصنف الجديد.

مثال

قبل إعادة التصميم

يحتوي الصنف Person على عددٍ من الحقول كاسم الشخص (name) ورمز منطقة المكتب (officeAreaCode) ورقمه (officeNumber)، وتابعًا للحصول على هذا الرقم باسم getTelephoneNumber، كما في مخطط الأصناف الآتي:

الصنف Person يحتوي على عددٍ من الحقول كاسم الشخص (name) ورمز منطقة المكتب (officeAreaCode) ورقمه (officeNumber)، وتابعًا للحصول على هذا الرقم باسم getTelephoneNumber.
الصنف Person يحتوي على عددٍ من الحقول كاسم الشخص (name) ورمز منطقة المكتب (officeAreaCode) ورقمه (officeNumber)، وتابعًا للحصول على هذا الرقم باسم getTelephoneNumber.

بعد إعادة التصميم

أصبح هنالك صنفٌ مخصَّصٌ للرقم الهاتفي (TelephoneNumber) يشمل كلَّ الحقول والتوابع المتعلقة به، وبقي الصنف الأصليّ Person محتويًا على ما تبقى من الحقول والتوابع، أي يصبح الصنفان بالشكل:

الصنف Person يحتوي على حقلٍ واحدٍ باسم name وتابعٍٍ للحصول على رقم الهاتف getTelephoneNumber، أمّا الصنف TelephoneNumber فهو يحتوي على حقلين باسم officeAreaCode و officeNumber بالإضافة إلى التابع السابق getTelephoneNumber.
الصنف Person يحتوي على حقلٍ واحدٍ باسم name وتابعٍٍ للحصول على رقم الهاتف getTelephoneNumber، أمّا الصنف TelephoneNumber فهو يحتوي على حقلين باسم officeAreaCode و officeNumber بالإضافة إلى التابع السابق getTelephoneNumber.

لم إعادة التصميم؟

تبدأ الأصناف بسيطةً وواضحةً وتقوم بمهامها الخاصّة كلٌّ على حِدة، ولكن سرعان ما يتوسَّع البرنامج ليُضاف حقلٌ (field) هنا وتابعٌ (method) هناك، ليصبح على عاتق الصنف الواحد -في النهاية- عددٌ كبيرٌ من المهام التي يمكن توزيعها على صنفين على الأقل.

فوائد تطبيق الحل

  • تساعد آلية إعادة التصميم هذه على الالتزام بمبدأ المسؤولية الواحدة (Single Responsibility Principle) مما يجعل الشيفرة أكثرَ وضوحًا وبساطةً.
  • تكون الأصناف ذات المهمة الواحدة (لكلِّ صنفٍ) أكثر وثوقيّة (reliable) وقابليّةً لإحداث التغييرات؛ فليكن مثلًا أحد الأصناف مسؤولًا عن عشر مهامٍ مختلفةٍ، سيشكِّل عندئذٍ إحداثُ تغييرٍ على هذا الصنف (بهدف تحسين مهمةٍ واحدةٍ) خطرًا على تسع مهامٍ أخرى بالطرف المقابل لذلك التحسين.

مساوئ تطبيق الحل

عند التطبيق المفرط لهذه التقنية ستحصل على عددٍ كبيرٍ من الأصناف ولا بُدَّ حينئذٍ من اللجوء إلى تضمين الصنف (Inline Class).

آلية الحل

قبل البدء بالحل، يجب التفكير أولًا بكيفية تقسيم مهام هذا الصنف، ثم اتباع الخطوات الآتية:

  1. إنشاء صنفٍ جديد لاحتواء المهمة التي يُرغب بفصلها عن الصنف الحاليّ.
  2. ربط الصنفين بعلاقةٍ أحاديّة الاتجاه (unidirectional) وذلك لإتاحة استخدام الصنف الجديد دون مشاكل تُذكَر، أمّا إن كان من الضروري الربط ما بين الصنفين بعلاقة ثنائيّة الاتجاه (bidirectional) فلا مشكلة في ذلك مؤقتًا.
  3. الاستفادة من تقنيتي نقل الحقول (Move Fields) ونقل التوابع (Move Methods) لنقل الحقول والتوابع المرتبطة بمهمة الصنف الجديد إليه، ومن الأفضل -بالنسبة للتوابع- البدءُ بنقل التوابع الخاصّة (private) للتقليل من احتمال حدوث الأخطاء، ويكون النقل عبر خطواتٍ صغيرةٍ مع ضرورة اختبار النتائج بعد كلِّ عملية نقلٍ لتجنُّب الوقوع بوابلٍ من الأخطاء المتشابكة وتعذُّر حلها في النهاية! وبعد الانتهاء من النقل بأكمله، عليك بإلقاء نظرةٍ شاملةٍ على الأصناف الناتجة، فمن الممكن أن تُعيد تسمية الصنف الأصليّ لتصبح أكثر وضوحًا، وتتأكَّد من إمكانيّة التخلص من علاقة الربط ثنائيّة الاتجاه ما بين الصنفين في حال وجودها.
  4. ضمان الوصول إلى الصنف الجديد من خارجه، إذ من الممكن إخفاء الصنف كليًا عن العميل بجعله خاصًّا (private) وإدارته عبر الحقول المتبقية في الصنف السابق (الصنف الأصلي)، أو من الممكن جعله عامًّا (public) وإعطاء العميل إمكانيّة تغيير القيم مباشرةً. يعتمد قرار تحديد الوصول إليه (عامًا أو خاصًّا) على مستوى الأمان المطلوب للصنف الأصليّ عند حدوث بعض التغييرات غير المتوقَّعة في قيم الصنف الجديد.

انظر أيضًا

مصادر