Kotlin: عالمين في لغة واحدة
\n\nهل تساءلت يومًا لماذا يكتب بعض المطورين بلغة Kotlin كما لو كانت Java محسّنة، بينما يحول آخرون الكود إلى سلسلة من تعابير lambda وسلاسل الاستدعاءات؟ الإجابة بسيطة: Kotlin هي لغة متعددة النماذج، تتعامل بشكل ممتاز مع كل من البرمجة كائنية التوجه (OOP) والبرمجة الوظيفية (FP).
\n\nولكن كيف لا يضيع المبتدئ في هذا التنوع؟ وكيف لا يقع المطور المتمرس في فخ "كود السباغيتي" بسبب خلط الأنماط؟ في هذا المقال، سنشرح الفروق بين هذين النهجين، وأين وكيف نستخدم كل منهما، وكيف يساعدنا Kotlin في الجمع بين أفضل جوانبهما. استعدوا: سيكون هناك الكثير من الأكواد ولا مجال للملل.
\n\nإذا كنت تتعلم Kotlin لتطوير تطبيقات Android أو الباك إند، فإن فهم هذه النماذج هو تذكرتك لعالم من الكود النظيف والقابل للقراءة والصيانة. هيا بنا!
\n\nKotlin كائني التوجه: الكلاسيكية في غلاف حديث
\n\nالنهج الكائني التوجه يدور حول الكيانات. لديك كلاسات، والكلاسات لها خصائص وطرق. كل ما تفعله البرنامج هو تفاعل بين الكائنات. Kotlin يأخذ أفضل ما في Java، لكنه يضيف السكر: data class، object، الخصائص الكسولة وغيرها الكثير.
الكلاسات والوراثة: مثال
\n\nتخيل أننا نكتب نظامًا لمتجر إلكتروني. النهج الكائني سيبدو هكذا:
\n\n// كلاس أساسي\nopen class Product(val name: String, val price: Double) {\n open fun getDescription(): String {\n return "$name يكلف $price روبل"\n }\n}\n\n// وراثة\nclass DiscountedProduct(name: String, price: Double, val discount: Double) : Product(name, price) {\n override fun getDescription(): String {\n val finalPrice = price * (1 - discount / 100)\n return "$name بخصم $discount% يكلف ${"%.2f".format(finalPrice)} روبل"\n }\n}\n\nfun main() {\n val apple = Product("تفاحة", 50.0)\n val saleApple = DiscountedProduct("تفاحة", 50.0, 20.0)\n \n println(apple.getDescription()) // تفاحة يكلف 50.0 روبل\n println(saleApple.getDescription()) // تفاحة بخصم 20% يكلف 40.00 روبل\n}\n\nهنا كل شيء منطقي: هناك تسلسل هرمي، تعدد أشكال، تغليف. لكن هناك عيوب: يصبح الكود ثقيلاً إذا كان هناك العديد من الكلاسات. وإذا أردنا ببساطة تطبيق خصم على أي منتج، فسنضطر إلى إنشاء كلاسات فرعية.
\n\nمتى يكون OOP هو المسيطر؟
\n- \n
- نماذج الأعمال المعقدة — عندما يكون للكيانات حالات وسلوكيات متعددة. \n
- مكونات واجهة المستخدم — Activity، Fragment، View — كلها OOP كلاسيكي. \n
- العمل مع قواعد البيانات — ORM (مثل Room) تستخدم الانعكاس والتعليقات التوضيحية المرتبطة بالكلاسات. \n
Kotlin الوظيفي: الإيجاز والأمان
\n\nالبرمجة الوظيفية تدور حول الحسابات، وليس الحالات. بدلاً من تغيير الكائنات، نستخدم بيانات غير قابلة للتغيير ودوال نقية. Kotlin لا تجبرك على الكتابة بأسلوب وظيفي، لكنها توفر لك جميع الأدوات لذلك: تعابير lambda، دوال الترتيب الأعلى، تركيبات شبيهة بالـ monad (مثل Result).
دوال الترتيب الأعلى: مثال
\n\nدعنا نحل نفس مشكلة الخصم، ولكن بطريقة وظيفية:
\n\ndata class Product(val name: String, val price: Double)\n\nfun applyDiscount(discount: Double): (Product) -> Product = { product ->\n val finalPrice = product.price * (1 - discount / 100)\n product.copy(price = finalPrice)\n}\n\nfun main() {\n val apple = Product("تفاحة", 50.0)\n val saleApple = applyDiscount(20.0)(apple)\n \n println("${apple.name} يكلف ${apple.price} روبل") // تفاحة يكلف 50.0 روبل\n println("${saleApple.name} بخصم يكلف ${saleApple.price} روبل") // تفاحة بخصم يكلف 40.0 روبل\n}\n\nلاحظ: لم ننشئ كلاسًا جديدًا. نحن ببساطة نمرر البيانات عبر دالة