حقن التبعيات (Dependency Injection) في Kotlin: دليل شامل

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة إلى Dependency Injection في Kotlin



تتطلب التطوير الحديث بلغة Kotlin إدارة فعالة للتبعيات بين الفئات. Dependency Injection (DI) هو نمط تصميم يسمح بتمرير تبعيات الكائن من الخارج، بدلاً من إنشائها داخلياً. هذا يقلل من ترابط الكود، ويبسط الاختبار، ويجعل التطبيق أكثر مرونة.



في هذه المقالة، سنشرح ما هو حقن التبعيات، ولماذا هو ضروري، وسنتناول ثلاث طرق لتطبيقه في Kotlin: الحقن اليدوي، استخدام مكتبة Hilt، وإطار العمل الخفيف Koin. ستكون المادة مفيدة لكل من المبتدئين والمطورين ذوي الخبرة الذين يرغبون في تنظيم بنية مشاريعهم.



أساسيات Dependency Injection



المشكلة بدون DI



تخيل فئة UserService التي تقوم بإنشاء مثيل UserRepository مباشرة:



class UserService {    private val repository = UserRepository() // ارتباط صارم

fun getUser(id: Int): User { return repository.findById(id) }}


من الصعب اختبار هذا الكود: لا يمكنك استبدال UserRepository بكائن mock. بالإضافة إلى ذلك، عند تغيير مُنشئ UserRepository، ستحتاج إلى تعديل جميع الأماكن التي يتم إنشاؤه فيها.



الحل: الحقن عبر المُنشئ



أبسط طريقة لتطبيق DI هي تمرير التبعية عبر المُنشئ:



class UserService(private val repository: UserRepository) {    fun getUser(id: Int): User {        return repository.findById(id)    }}


الآن UserService لا يعرف كيف يتم إنشاء UserRepository. يمكنك تمرير أي تطبيق — قاعدة بيانات حقيقية، طبقة وهمية، أو mock للاختبارات.



عكس التحكم (IoC)



يرتبط DI ارتباطاً وثيقاً بمبدأ Inversion of Control (IoC). بدلاً من أن تتحكم الفئة نفسها في إنشاء التبعيات، يتم نقل التحكم إلى حاوية خارجية أو مصنع. هذا يجعل النظام ضعيف الارتباط وسهل التوسيع.



الحقن اليدوي للتبعيات (Manual DI)



للمشاريع الصغيرة أو الأغراض التعليمية، يمكن الاستغناء عن الأطر. سنقوم بإنشاء حاوية تبعيات بسيطة يدوياً.



مثال: حاوية التبعيات



// تعريف واجهة المستودعinterface UserRepository {    fun findById(id: Int): User}

// التطبيقclass UserRepositoryImpl : UserRepository { override fun findById(id: Int): User { // منطق الحصول على المستخدم من قاعدة البيانات return User(id, "User$id") }}

// الحاوية التي تجمع جميع التبعياتclass AppContainer { val userRepository: UserRepository = UserRepositoryImpl() val userService: UserService by lazy { UserService(userRepository) }}

// الاستخدامfun main() { val container = AppContainer() val service = container.userService println(service.getUser(1))}


المزايا: تحكم كامل، لا تبعيات خارجية، سهولة الفهم.

العيوب: مع نمو المشروع، تكبر الحاوية ويصبح من الصعب إدارة دورة حياة الكائنات ونطاقاتها.



حقن التبعيات باستخدام Hilt



Hilt هي مكتبة رسمية من Google لـ DI في تطبيقات Android بلغة Kotlin. وهي مبنية على أساس Dagger، لكنها أبسط بكثير في الإعداد.



إعداد Hilt



أضف في build.gradle.kts (مستوى المشروع):



plugins {    id("com.google.dagger.hilt.android") version "2.48" apply false}


في build.gradle.kts لوحدة التطبيق:



plugins {    id("com.google.dagger.hilt.android")}

dependencies { implementation("com.google.dagger:hilt-android:2.48") kapt("com.google.dagger:hilt-compiler:2.48")

المدونات

توصيات الكتب