أستمع الى المقال

تعرّفنا في الدرس السابق، على كيفية عمل تغليف Encapsulation للخاصيّات و الدوال و الأصناف داخل ملف كوتلن عبر استخدام محدّدات الوصول Access Modifiers والـ Setters والـ Getters. في هذا الدرس، سنتعرف على طريقة تمكّننا من تنظيم الملفات والأصناف في برامجنا في حِزم Packages (مجلدات). وبذلك يتوفّر لنا تحكّم إضافي في تقييد الوصول للأصناف وأعضائِها، عبر وضع الملفّات والأصناف التي تقوم بعمل متشابه داخل حِزمة واحدة.

ما هي الحِزم Packages:

تحتوي مشاريع كوتلن الكبيرة على الآلاف من الملفّات والأصناف. سيكون من الصّعب إدارتها إذا تمّ تخزينها كلّها في نفس المجلّد. توفّر الحِزم آلية لتجميع الملفّات والأصناف معًا في نفس المجلّد (الحزمة). يمكن أن يحتوي المجلّد على مجلّدات أخرى، بطريقة تشبه نظام الملفّات في أنظمة التّشغيل مثل ويندوز أو ماك أو لينوكس.

والفائدة من وضع الملفات والأصناف في حِزم، هي كالآتي:

  • تجميع الأصناف ذات الصّلة معاً، مما يسهّل معرفة مكان صِنف معين.
  • تجنّب التضارب في أسماء الأصناف. حيث يمكن تسمية الأصناف بنفس الأسم، طالما تم وضعُها في حِزم مختلفة. ﻷن أسم الحزمة، هو ما يميّز الصنف.
  • مزيداً من التحكم في الوصول إلى الأصناف وأعضائها باستخدام محدّدات الوصول.

بنية مشروع كوتلن:

لفهم الكلام النّظري أعلاه، فلننظر إلى الصورة التالية من مشروع بسيط يحاكي لعبة كاسحة الألغام Minesweeper. يتم تنفيذ تطبيق اللعبة هذا، من سطر الأوامر ولا توجد به واجهة رسومية. لذلك يحتوي على ملف رئيسي واحد وأربعة أصناف فقط:

كما نرى في الصورة، يحتوي التطبيق على شجرة بسيطة تتكون من:

  • المجلد الرئيسي src. في هذا المجلد نضع كل الملفّات والأصناف التي ننشئُها.
  • داخل مجلد src، وضعنا 4 أصناف تُمثّل كائنات مختلفة، ولدى كل منها مهام محدّدة. بالإضافة لملف وضعنا به دالة التشغيل الرئيسية ()main. وسيرتب برنامج IntelliJ الملفات والأصناف حسب الحروف الأبجدية ﻷسماءهم.

التطبيق في حالته البسيطة هذه، لن يسبّب مشكلة إذا تركنا كلّ الأصناف والملفات في المجلد الرئيسي src. ولكن لاحقًا إذا قرّرنا تحديث التطبيق وإضافة المزيد من الأصناف والملفات حتى وصلتَ إلى العشرات منها، قد نواجه مشكلة في إيجاد الأصناف التي تقوم بعمل مشابه للتّعديل أو العمل عليها. 

ﻷنه قد يكون أحد الأصناف في أعلى شجرة الترتيب، والآخر في آخرها. في هذه الحالة سنضيّع معظم وقتنا في البحث عن هذه الملفات والأصناف. لتجنب ذلك، يمكننا إنشاء حِزم ووضع الملفات والأصناف التي تقوم بعمل مشابه بها.

إنشاءُ حِزمة:

يمكننا التّعديل على برنامجنا وإنشاء حِزم مناسبة للأصناف والملفات وهو بذلك سيكون جاهزًا أيضًا ﻷية إضافات مستقبلية. ويجب إنشاء الحِزمة الجديدة داخل مجلد src. لذا نضغط بزر الماوس اﻷيمن على مجلد src، ثم نختار new من القائمة، ثم package، كالتالي:

ستظهر نافذة صغيرة والتي نضع بها الإسم الذي إخترناه. تُكتب اسماء الحِزم بحروف إنجليزية صغيرة، ﻷن هذا هو المتعارف والمتفق عليه. ندخل الاسم ونضغط Enter،  كالتالي:

تم إنشاء الحِزمة main. الآن يمكننا نقل الملف الرئيسي main.kt إليها، كما يَظهر في الصورة التالية:

سنفعل المثل لبقية الأصناف، ليكون الشكل النهائي كالتالي:

  1. الحزمة data: وهي حزمة سنضع بها البيانات التي يستقبلها التطبيق من الخارج، والتي يمثّلها الصّنف UserInput. اخترنا الأسم data لأنه يعني بيانات باللغة الإنجليزية.
  2. الحزمة main: هنا سنضع الملف الرئيسي للتطبيق، والذي يحتوي على الدّالة ()main.
  3. الحزمة mines: سنضع داخل هذه الحزمة، الأصناف التي تُمثّل الألغام في تطبيقنا.
  4. الحزمة utils: هنا سنضع كل الأصناف والملفات التي تعتبر ملفات مساعدة داخل التطبيق.

نلاحظ في الصورة أيضاً، أن هناك خطوط حمراء تحت أغلب الحزم والملفات. هذا لأنّنا بعد أن نقلنا الأصناف إلى حِزم غير حزمة src الرئيسية، لم تعد الإشارات إلى الأصناف الصالحة لأن البرنامج لا يعرف أين يجدها. وبسبب هذا، لن يتم تجميع وتنفيذ هذا البرنامج من الأساس. ومهمتنا الآن، هي إصلاح الخطأ بوضع رابط إلى كل الأصناف والدوال والخاصيات صراحة.

الكلمة المفتاحية package:

قبل إصلاح الخطأ، يجب أولًا أن نكتب اسم الحزمة في أعلى كل ملف باستخدام الكلمة المفتاحية package، كالتالي:

ﻷن ملف main.kt موجود داخل الحزمة main، كتبنا اسم الحزمة في أعلى الملف. سنفعل المثل مع كل الأصناف المتبقية، بكتابة اسم الحزمة التي توجد بها في أعلى ملفاتها.

الكلمة المفتاحية import:

والآن إذا أردنا استخدام الدالة ()main الموجودة داخل الملف main.kt في ملف آخر، يجب علينا تضمين Import الدّالة بوضع رابط يحتوي على اسم الملف ثم نقطة (.) ثم اسم الدالة، كالتالي:

import main.main

الكلمة المفتاحية import، ثم كلمة main الأولى التي تُمثل اسم الحزمة، ثم كلمة main الثانية، والتي تُمثل اسم الدّالة. بالتالي، لإصلاح الخطأ الذي يظهر في تطبيقنا بعد نقل الملفات، علينا أن نضع رابط مباشر إلى كل صنف أو دالة أو خاصيّة إذا قمنا باستخدامها في أي ملف آخر موجود في حزمة مختلفة.

إذا ألقينا نظرة أخرى على الصورة أعلاه، سنجد أن هناك استدعائين يظهران باللون الأحمر، أحدهما استدعاء لدالة اسمها ()minesUserInput والآخر لإنشاء كائن من صنف اسمه MinesField. علينا تعريفهما في أعلى الملف باستخدام كلمة import، حتى يتمكن ملف main.kt من استخدامها، كالتالي:

وضعنا في أعلى الملف، عبارة التضمين التالية:

import data.UserInput.minesUserInput

العبارة تعني: إذهب إلى الحزمة data ثم الصنف UserInput ثم بداخل الصنف ستجد الدالة minesUserInput. وبعد وضع العبارة تحول لون الدالة من الأحمر إلى الأبيض، للدلالة على أنه لا يوجد خطأ في استخدام الدالة بعد الآن.

ميزة عمل import عبر برنامج IntelliJ:

كما نرى في الصورة أيضًا، هناك العديد من الأخطاء الأخرى التي يسببها عدم معرفة ملف main.kt، أين يمكنه إيجاد الأصناف والدوال والخاصيّات التي استخدمناها داخله. إذًا، علينا إضافة تضمينات تُشير إلى مكان وجود كل منها هي الأخرى. ولكن هذه المرة بدل كتابة التضمين يدويًا وإضاعة الوقت، سنجعل برنامج IntelliJ يساعدنا، كالتالي:

بمجرد وضع مؤشر الماوس على اسم الصنف الذي يظهر باللون الأحمر، ظهرت نافذة وبها كلمة import. بالضغط على الكلمة، سيتم إضافة رابط تضمين الصنف MinesField في أعلى الملف.

ثم سنجد أن برنامج IntelliJ سيمر على الشفرات التي تحتاج إلى جلب واحدة تلو الأخرى، ويقترح علينا تضمينها عبر الضغط على Alt+Enter على لوحة المفاتيح، كما يظهر في الصورة التالية:

وسنستمر على هذا المنوال، حتى يتم تضمين كل الأصناف والدوال والخاصيّات التي استخدمناها داخل كل الملفات في التطبيق، وتختفي الأخطاء. لتكون النتيجة النهائية، كالتالي:

تضمين الأصناف من مكتبة كوتلن القياسية:

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

فمثلًا، إذا أردنا الحصول على أرقام عشوائية، يمكننا تضمين الصنف Random الذي  يوجد في حزمة random من مكتبة كوتلن، كالتالي:

import kotlin.random.Random

ويمكن استخدام الصنف Random كالتالي:

بما أنه تم تضمين الصنف Random، يمكن استخدام الدالة ()nextInt التي توجد بداخله. وهي الدالة التي سنرسل إليها قيمتين من النوع Int، لتعيد لنا رقم عشوائي بين الرقمين. نحن هنا طلبنا منها أن تعيد رقم عشوائي بين الرقمين 1 و 20. تم طباعة الرقم العشوائي 5 مرات، ﻷن كتلة for قامت بتنفيذ شفرة الدالة ()nextInt و دالة الطباعة ()print، لخمس مرات. وهو شرط النطاق العددي (5..1) الذي وضعناه بين قوسيها.

تضمين كل شيء من حزمة معينة:

بعد تضمين الصنف Random، يمكننا استخدامه هو فقط في ملفنا. ولكن لتضمين كل ما تحتويه حزمة random، يمكننا ذلك عبر استخدام علامة النجمة (*)، كالتالي:

import kotlin.random.*

الخلاصة:

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

يمكن الحصول على شفرة تطبيق كاسحة الألغام Minesweeper على هذا الرابط في موقع GitHub.

هذا الدرس هو جزءٌ من سلسلة تعليم مبادئ البرمجة بلغة كوتلن. لمُتابعة الدروس منذ البداية ومُشاهدة فهرس المحتويات يمكنك الانتقال إلى الدرس الأول من هنا.

هل أعجبك المحتوى وتريد المزيد منه يصل إلى صندوق بريدك الإلكتروني بشكلٍ دوري؟
انضم إلى قائمة من يقدّرون محتوى إكسڤار واشترك بنشرتنا البريدية.