الأساليب الثابتة في Kotlin: كيف لا يضيع مطور Java في عالم object و companion
\n\nإذا كنت تكتب بلغة Java وتبدأ للتو في تعلم Kotlin، فمن المحتمل أنك تساءلت: "أين static هنا؟". في Java اعتدنا على كتابة public static void main() أو MathUtils.max() - إنها مريحة وبسيطة ولا تتطلب إنشاء كائن. لكن في Kotlin، الكلمة المفتاحية static غير موجودة. إطلاقاً. بتاتاً.
لا داعي للذعر. لم يصب مطورو Kotlin بالجنون - لقد قرروا ببساطة أنه يمكن تنفيذ الأساليب الثابتة بشكل أكثر أناقة، دون حالة عامة وبهندسة معمارية أكثر وضوحاً. في هذه المقالة، سنستعرض جميع الطرق لاستبدال Java static في Kotlin: من الدوال البسيطة على مستوى الحزمة إلى companion object القوي. ستتعرف على متى تستخدم كل منها، وسترى أمثلة حية على الكود.
هيا بنا! 🚀
\n\n\n\n
لماذا لا يوجد static في Kotlin؟ (وهذا أمر جيد)
\n\nفي Java، static هو في الأساس متغير عام أو أسلوب مرتبط بالفئة وليس بنسخة منه. هذا مفيد للأدوات المساعدة، لكنه ينتهك مبادئ البرمجة الشيئية: لا يمكن تجاوز الأعضاء الثابتة، ويصعب اختبارها، وتخلق ارتباطات صلبة.
يشجع Kotlin على نهج أنظف: يمكن أن توجد الدوال والخصائص على مستوى الحزمة (بدون فئة على الإطلاق!) أو يتم تنظيمها في كائنات مفردة (object-singletons). وإذا كنت بحاجة إلى ربط أسلوب بفئة (كما في Java)، فاستخدم companion object. دعنا نستعرض كل خيار.
\n\n
الطريقة 1: دوال على مستوى الحزمة (الأبسط)
\n\nفي Kotlin، يمكنك تعريف دالة أو خاصية ببساطة في ملف، خارج الفئة. هذا مشابه للأسلوب الثابت في Java، ولكن بدون غلاف فئة مساعدة غير ضروري.
\n\nمثال:
\n\n// File: MathUtils.kt\npackage com.example.utils\n\nfun max(a: Int, b: Int): Int {\n return if (a > b) a else b\n}\n\nval PI = 3.14159 // ثابت على مستوى الحزمة\n\nالآن يمكن استدعاء هذه الدالة من أي مكان (بعد الاستيراد):
\n\nimport com.example.utils.max\nimport com.example.utils.PI\n\nfun main() {\n println(max(10, 20)) // 20\n println(PI) // 3.14159\n}\n\nمتى تستخدم: للدوال المساعدة البسيطة والثوابت التي لا تتطلب تجميعاً في فئة. هذه هي أسهل طريقة للحصول على سلوك "ثابت".
\n\n\n\n
الطريقة 2: كائن مفرد (object-singleton) (لمجموعة من الدوال ذات الصلة)
\n\nإذا كنت بحاجة إلى تجميع عدة أساليب ثابتة معاً (مثل MathUtils في Java)، فاستخدم object. هذا كائن مفرد - نسخة واحدة يتم إنشاؤها تلقائياً عند أول استخدام.
مثال:
\n\nobject StringUtils {\n fun isEmpty(str: String?): Boolean {\n return str.isNullOrEmpty()\n }\n\n fun capitalizeFirst(str: String): String {\n return str.replaceFirstChar { it.uppercase() }\n }\n\n const val EMPTY_STRING = ""\n}\n\nالاستخدام:
\n\nfun main() {\n println(StringUtils.isEmpty(null)) // true\n println(StringUtils.capitalizeFirst("kotlin")) // Kotlin\n println(StringUtils.EMPTY_STRING) // ""\n}\n\nهام: object هو فئة كاملة. يمكنه تنفيذ واجهات، ولديه مُهيئات، وحتى الوراثة من فئات أخرى. لكنه لا يمكن أن يحتوي على مُنشئات (باستثناء الخاص).
\n\n
الطريقة 3: Companion object (للأساليب المرتبطة بالفئة)
\n\nهذا هو أقرب مكافئ لـ Java static داخل الفئة. companion object هو كائن مرافق يعيش داخل الفئة. يتم استدعاء أساليبه وخصائصه عبر اسم الفئة، مثل الأساليب الثابتة.
مثال:
\n\nclass User(val name: String, val age: Int) {\n compan