كثير من المبرمجين لا يستخدموا ال packages بشكل جيد، فتارة تجد package باسم لا يدل على محتواها، وتاره تجد package واحد بها كل الكلاسات في البرنامج، وتارة ترى أن المبرمج يستخدم ال Default Package (أي لم يقم بعمل اي package من الأساس) وهذا خطأ كبير في التطبيقات الكبيرة.
فالمعامل الأول والمهم للحكم ان تطبيقك مصمم جيداً هو درجة اخفاء كل package التفاصيل عن الأخرى، أي أن الPackage الجيد يخفي كل تفاصيل الImplementations ويقدم API سهله للPackage (أو Module) الأخرى. هذا المعامل معروف بالاسم Information Hiding أو Encapsulation وهو من أهم أساسيات تطوير البرامج Software Design.
هذه المقالة جزء من سلسلة كيف تحترف لغة الجافا وهي موجهة لأي مطور OOP ويستخدم لغة الجافا
- الإسلوب الصحيح لكتابه Utility Classes
- هل مللت من دالة البناء Constructor ؟
- استخدام ال Builder Pattern في دالة البناء
- لا تستخدم Public الا وقت الحاجة
- كيف تصمم الPackages جيداً في تطبيقات جافا (المقال الحالي)
- جافا دائماً Passing by Value
- نظرة حول الدالة Equals
- خارطة طريق لتعلم الجافا
مفهوم ال Information Hiding في تصميم البرمجيات
الInformation Hiding مهم لعدة أسباب حيث أنه يسمح لك بالعمل على Module واحد بينما يسمح للمطورين معك على Modules أخرى، وهكذا تستطيع التطوير Developed وحتى الاختبارات والتحسينات testing/optimizations واستخدامه وتعديل الImplementation بدون اخلال شيء (break) في الModule الأخرى.
هذا يساعد على سرعه التطوير لأنه يمكن أن يعمل أكثر من مطور في نفس الوقت In Parallel، أيضاً في عمليات الDebugging سوف تكون أسهل لأنك تركز على Module واحد وبنفس الأمر في عمليات اختبار وتعديل الأداء Performance Tuning.
من المزايا أيضاً للInformation Hiding هو اعادة الاستخدام Reuse حيث أن تلك الModule قد لا تكون مرتبطة ببضعها بشكل قوي وهكذا قد يساعدك على اعادة استخدامها في أماكن أخرى بخلاف الموضع الأول. أيضاً هذا يقلل قليلاً من مخاطر بناء نظام ضخم Decrease Risk لأنك تبنى على دفعات (Modules) قد تنجح فيما بعد وان فشل ذلك النظام الكبير.
جافا تعطينا عدة أدوات تساعدنا في Information Hiding (من خلال ال Access Control) والتي تستطيع استخدامها في الClasses و ال Interface و الMembers سواء كانت متغيرات أو دوال في الكلاس. الاستخدام الشائع الذي تعلمه كثير من المبرمجين (private لكل المتغيرات) هو قد ينجح في حالات وفي حالات قد لا يكون له نفع، والذي يحكم هذا الأمر هو مكان وجود الكلاس وما هى درجة الوصول له وهذا مهم ، لذلك هذه المقاله مهمه حيث أنك تضع اللبنة الأولى في تصميم Module مناسبة للكلاسات حتى تقوم بعد ذلك بتطبيق الInformation Hiding بالشكل الصحيح.
السؤال المطروح الآن هو كيف اقسم ال Package في التطبيق؟ وفي الغالب للتطبيقات التي تقوم بعملها توجد طريقتين لهذا الأمر.
التقسيم بواسطة الخصائص أو المزايا Package By Feature
وفي هذا النوع سوف تكون كل package تمثل ميزة Feature في النظام، وكل الكلاسات التي تتعلق بهذه الميزه سوف تضعها فيها، هكذا سيكون الPackage يحتوي على شيء متعلق بهذه الميزة High Cohesion وتكون قد طبقت مفهوم الModular بشكل جيد والأهم من ذلك هو ان هذا التصميم يقلل التعامل مع الPackages الأخرى Minimal Coupling، فأي Item متعلق سوف يكون هنا ولن تجده موزع في مجلد التطبيق، وهكذا اذا اردت حذف هذه الميزة مثلاً من تطبيقك فكل ما عليك هو حذف ذلك المجلد Package (وحل المشاكل التي تنتج من الAPI المستدعاة من ذلك الPackage) ولكن في الأخير العملية سهله للغاية ومريحة للمبرمجين.
في هذا النوع Package By Feature سوف تكون أسماء الPackge تدل على محتواها أو المشكلة التي تحلها وان كانت بمصطلحات المشروع Problem Domain، على سبيل التطبيق تطبيق يتعامل مع المخدرات قد يحتوي على هذه الPackges:
- com.app.doctor
- com.app.drug
- com.app.patient
- com.app.presription
- com.app.report
- com.app.security
- com.app.webmaster
- com.app.util
في داخل كل من هذه الPackges ستجد كل شيء متعلق بها، مثلاً لو نظرنا لل com.app.doctor ستجد اكواد الModel وال GUI والاتصال بالقاعدة وكل شيء متعلق بها:
- DoctorAction.java – an action or controller object
- Doctor.java – a Model Object
- DoctorDAO.java – Data Access Object
- database items – SQL statements
- user interface items – swing, JSP etc
من المزايا لهذه الطريقة وهي ان عملت مع مبرمج مبتدئ يمكنك ان تعطيه Package يعمل عليه ، هكذا تستطيع العمل وانت مطمئن أنه لا يعيث في الأرض فساداً طالما هو محصور هنا، حقيقة ميزة جيدة للفرق البرمجية.
التقسيم بواسطة الطبقات Package By Layer
هذه الطريقة تعتمد على مفهوم الطبيقات الثلاثه في تقسيم الpackage ، وبالتالي ستجد package خاص للdatabase وpackage خاص لل GUI وهكذا، على سبيل المثال:
- com.app.action
- com.app.model
- com.app.dao
- com.app.util
لاحظ أن أي ميزة Feature في البرنامج تجدها موزعه Spread Out في كل هذه المجلدات، فكل مجلد يحتوي كلاسات لا علاقه لها بها ، فقط بسبب انها تؤدي نفس الوظيفة، هذه التصميم يقلل من ال Cohesion وقلل أيضاً من ال Modularity وجعل التعامل بين هذه الPackages قوي High Coupling ، وكنتيجة لذلك اذا أردت أن تعدل على Feature ما فأنت تحتاج للبحث في كل هذه المجلدات لكي تعدل تلك الميزه ، وأيضاَ اذا أردت حذفها فالأمر متعب حقاً.
لذلك عندما تصمم ال Package في التطبيق، اختر الطريقة الأولى By Feature وفضله على الثانيه لأنها تقدم لك Higher Modularity (وبمزايها High Cohesion و Low Coupling) ، وتقدم لك طريقة سهله لأدارة الكود وتصفحه Easier Code Navigation ، وايضاً تقدم لك نظرة عامه جيدة على المشروع High Level Abstraction.
أنظر الأن وحاول ايجاد الفرق بين التصميمين وأوجد أيهما أفضل ؟ ( الLayer على اليمين , الFeature على اليسار)
الأن بعد مرور وقت في التطوير وكبر حجم المشروع سوف تجد طريقة ال Layer بهذا الشكل:
بينما الطريقة الأولى By Feature سوف تكون بهذا الشكل المتناسق:
كما تلاحظ الطريقة الثانية By Layer ليست جيدة وحقيقة لم أرى لها أي ميزه عندما تستخدم بمفردها الا التعقيد والملفات الكثيرة… ما أجمل الكود لو تصفحته وعرفت درجة الفصل بين الModules به.. أرجوا أن تتذكر ذلك وقت تصميمك لمشروع القادم أو عند عمل Refactoring لمشروعك الحالي.
بعض الأحيان قد تكون لديك أكثر من Feature تستخدم كلاس ما ففي تلك الحالة عليك بنقلها في مكان عام مناسب لتلك المزايا حتى تقوم بخدمتهم وقد تجد أنها أصبحت ك Layer أو Service (ان صح التعبير) وهذا شيء صحيح ويمكن وضعها ايضاً في مكتبة jar اذا أردت ذلك.
هذا اول الغيث، وأنت الآن في طريق تصميمك للبرنامج الرائع Well Designed Modules لكن ينقصك شيء واحد وهو أن “لا تستخدم public أبداً الا وقت الحاجة” وهذا هو عنوان المقاله القادمة ان شاء الله.
بسم الله الرحمن الرحيم
لا تتوقف اخى الفاضل رائع ومتابعيين بأذن الله تعالى- اسأل الله عز وجل بكل حرف فى كل مقالة لكم حسنة ومغفرة وحياة طيبة-امين
جزاكم الله كل خير
Thank you very much Wajdy Essam
it is very helpful
keep on man and break info out
جميله جدا المقاله ………………..لا تتوقف عن إفادة الجميع 🙂
شكرا لك اخي الفاضل ..
كما قلت يا أخي الطريقة الاولى by feature هي الافضل فكلما كبر المشروع تحس نفسك متحكم و مسيطر على مشروعك .
أما الطريقة الثانيةby layer فهي أحسن طريقة لترك المشروع .