مقدمة: ما هو حقن التبعية ولماذا هو ضروري في Kotlin؟
\nحقن التبعية (DI) هو نمط تصميم يجعل الكود أكثر مرونة وقابلية للاختبار والصيانة. بدلاً من أن يقوم الكائن بإنشاء تبعياته بنفسه، يقوم DI بتمرير (حقن) هذه التبعيات من الخارج. في Kotlin، بفضل تركيبته المختصرة وإمكانياته القوية، يصبح DI أداة أنيقة بشكل خاص.
\nتخيل أنك تكتب تطبيقًا لطلب البيتزا. لديك كلاس OrderService يجب أن يرسل إشعارات. بدون DI، سيبدو هكذا:
class OrderService {\n private val notifier = EmailNotifier() // ارتباط صارم\n\n fun placeOrder(order: Order) {\n // منطق الطلب\n notifier.send("تم استلام طلبك!")\n }\n}\nالمشكلة: لن تتمكن بسهولة من استبدال EmailNotifier بـ SmsNotifier أو اختبار OrderService دون إرسال بريد إلكتروني فعلي. يحل DI هذه المشكلة عن طريق حقن التبعية عبر المُنشئ:
class OrderService(private val notifier: Notifier) {\n fun placeOrder(order: Order) {\n notifier.send("تم استلام طلبك!")\n }\n}\nالآن OrderService لا يعرف كيف يتم إرسال الإشعار بالضبط. هذا هو جوهر DI: ارتباط ضعيف وقابلية عالية لإعادة الاستخدام.
الطرق الرئيسية لتنفيذ DI في Kotlin
\nتوجد ثلاث طرق رئيسية لحقن التبعيات في Kotlin: الحقن اليدوي، واستخدام المكتبات (Koin، Dagger 2)، والحقن عبر أطر العمل (مثل Spring). دعنا ننظر إلى كل منها عمليًا.
\n\n1. الحقن اليدوي للتبعيات (Manual DI)
\nأبسط طريقة هي تمرير التبعيات عبر المُنشئ أو الدوال الضابطة (setters). هذا لا يتطلب مكتبات إضافية وهو مثالي للمشاريع الصغيرة.
\nمثال: لننشئ خدمة بسيطة لمعالجة المدفوعات.
\n// واجهة بوابة الدفع\ninterface PaymentGateway {\n fun process(amount: Double): Boolean\n}\n\n// تنفيذ عبر PayPal\nclass PayPalGateway : PaymentGateway {\n override fun process(amount: Double): Boolean {\n println("معالجة الدفع $amount عبر PayPal")\n return true\n }\n}\n\n// خدمة الطلبات مع حقن التبعية\nclass OrderService(private val paymentGateway: PaymentGateway) {\n fun checkout(total: Double) {\n if (paymentGateway.process(total)) {\n println("تم تأكيد الطلب!")\n }\n }\n}\n\n// نقطة الدخول — "مصنع" أو "حاوية"\nfun main() {\n val gateway = PayPalGateway()\n val service = OrderService(gateway)\n service.checkout(100.0)\n}\nالإيجابيات: البساطة، التحكم الكامل، لا تبعيات على المكتبات.
\nالسلبيات: مع نمو المشروع، تصبح الإدارة اليدوية لجميع التبعيات معقدة (تحتاج إلى إنشاء "حاوية" أو "مصنع" يدويًا).
2. حقن التبعية باستخدام Koin
\nKoin هي مكتبة خفيفة الوزن لـ DI مكتوبة بلغة Kotlin. لا تستخدم الانعكاس (reflection) ولا تتطلب توليد كود، مما يجعلها مثالية للمشاريع الصغيرة والمتوسطة.
\nالتثبيت: أضف في build.gradle.kts:
implementation("io.insert-koin:koin-core:3.5.6")\nمثال على الاستخدام:
\nimport org.koin.core.context.startKoin\nimport org.koin.dsl.module\n\n// وحدة التبعيات\nval appModule = module {\n single<PaymentGateway> { PayPalGateway() }\n factory { OrderService(get()) } // get() تحصل تلقائيًا على PaymentGateway\n}\n\nfun main() {\n startKoin {\n modules(appModule)\n }\n\n // الحصول على الخدمة من الحاوية\n val service: OrderService = org.koin.core.component.get()\n service.checkout(200.0)\n}\nالمفاهيم الأساسية في Koin:
\n- \n
single— ينشئ مثيلًا واحدًا (singleton)