Home برمجة جافا الإسلوب الصحيح لكتابه Utility Classes
الإسلوب الصحيح لكتابه Utility Classes

الإسلوب الصحيح لكتابه Utility Classes

130
3

هناك الكثير من الدوال أو الثوابت نقوم بكتابتها ووضعها في كلاس ومن ثم نجد أن هناك كلاسات اخرى بحاجه لها، احد الحلول الخاطئة تماماً وهو نسخ ولصق تلك الدوال في اي كلاس كان في حاجه له، بالطبع الحل الصحيح وهو نقل هذه الدوال أو الثوابت الى كلاس عام يسهل للجميع الوصول اليه، تسمى هذه الكلاسات التي تحتوي على الدوال بالإسم Utility Classes بينما التي تحتوي على متغيرات فقط تسمى Constant Classes.

لذلك كثير من الأحيان قد تحتاج لعمل هذا  الكلاس وفيه مجموعه من الدوال والمتغيرات الstatic فقط ( كما توجد في الباكج java.lang.Math و java.util.Arrays ) ولن تحتاح لعمل كائن من الكلاس، فقط أن تريد ضم مجموعه من الدوال المتعلقه بشيء ما في كلاس معين. مثلاً دوال تتعامل مع عرض التاريخ أو مع المجلدات.

اذاً نريد أن نمنع الكلاينت من عمل كائن من هذا الكلاس، كيف السبيل لذلك؟ كما نعلم في أساسيات ال OOP في حال قمنا بعمل الكلاس ولم نقم بتزويده بداله بناء Constructor فيمكن أن يقوم المستخدم بعمل كائن منه وذلك بسبب أن المترجم سوف يزود الكلاس بدالة بناء افتراضية default constructor اذا لم يجد أي دالة بناء، أحد الحلول لمنع انشاء الكائن من الكلاس هي بجعل الكلاس abstract وبالتالي لا يستطيع أحد القيام بعمل كائن منه ولكن هذا لا يحبذ لأن الكلاس قد يتم الوراثه منه ويتم عمل الكائن بسهوله اضافه وهي الاهم أن المستخدم يخطئ ويظن ان الكلاس مصمم للوراثه منه.

الطريقة الافضل لمنع الكلاينت من انشاء كائن منه عن طريق تزويد الكلاس بدالة بناء private constructor، المثال التالي يبين ذلك:

لاحظ أننا قمنا بعمل throw لexception فقط حتى تضمن أنه لا يمكن عمل كائن من الكلاس سواء من داخله وخارجه وأنه سيحدث خطأ يوقف سير البرنامج اذا قام أحد بطريقة ما بانشاء الكائن ،،هكذا أصبح لدينا كلاس Utility لا يمكن انشاء كائن منه وفي نفس الوقت غير قابل للوراثه والسبب أن دالة البناء private والكلاس الابن يحتاج لهذه الدالة لكي يستطيع انشاء الكائن، لذلك لا يمكن الوراثه من ذلك الكلاس.

كأسلوب Convention في التسمية يفضل ان تتبع اسلوب واحد في تسمية ال Utility ، مثلاً أن تكتب DateHelper (ينتهي ب Helper) بالنسبة لي فأستخدم اللاحقه Util فهي أسهل في الفهم، مثلاً الكود التالي من أحدى ال FileUtil لأحد المشاريع -تم ازالة كثير من الدوال ووضع ال import العامة التي تنتهي بعلامه *- :

هذا ما يتعلق بكتابه الUtility Class بالنسبة للدوال ،، نأتي الأن لموضوع الثوابت ، وفي الحقيقة نجد أن هناك تصميم غير جيد منتشر منذ القدم لدى بعض مبرمجي الجافا وهو تعريف الثوابت في interface ومن ثم جعل الكلاسات التي تريد هذه الثوابت بعمل implement لهذا ال interface (هذا يسمى ب Constant Interface) ولا تحبذ هذه الطريقة بسبب الثوابت يفترض أن تكون جزءاً من عمل الكلاس Implementation ولكن بهذا الشكل سوف تكون جزءاً من الأشياء المتاحة في الكلاس Exported API، تخيل مثلاً انك في النسخه القادمة تريد ازالة ثابت منها فلن تستطيع حتى تحافظ على ال Compatibility في النسخ السابقة ، أيضاً لو كان هناك ابناء لهذا الكلاس فجيمعهم سوف يحمل هذه الثوابت معه حتى ولو لم يحتاجها.

لذلك الحل الأفضل للثوابت هي وضعها في Utility Class بدالة بناء private ، وبالنسبة لي افضل أن ينتهي اسمها ب Constants للدلالة على الثوابت بداخلها، على سبيل المثال:

كخلاصه تأكد من وضع private constructor لكل من ال Utility Class و ال Constant Class حتى تضمن عدم وراثتها وانشاء كائن منها، ولا تستخدم interface لحمل الثوابت فالClass أفضل منها.

(130)

وجدي عصام مهندس برمجيات مهتم بعلوم الحاسب وبالأخص مجال الخوارزميات وهندسة البرمجيات وحماية التطبيقات،

Comment(3)

    1. نعم يفضل جعل اي كلاس لا يدخل في عملية وراثه ان يكون final، ولكن بما أن ال private constructor تحمي ايضاً من انشاء الكائن من اي كلاس ابن ، لذلك يمكن ان تكون بنفس معنى final في هذه الحالة..

      على العموم للتعود على هذه ال practice والتي نحتاجها خصوصاً عندما نقوم بعمل Immutable سأقوم بوضع ال final على هذه ال utility .

      تحياتي اخي محمد :).

LEAVE YOUR COMMENT

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

مشاركة