Injection de dépendances en Kotlin : un guide simple pour débutants

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Qu'est-ce que l'injection de dépendances et pourquoi en a-t-on besoin en Kotlin ?



L'injection de dépendances (DI) est l'un des principes de conception clés dans le développement moderne, en particulier en Kotlin. Si vous débutez en programmation, ce concept peut sembler complexe. En réalité, c'est simple : l'injection de dépendances est une façon de fournir à un objet ses dépendances de l'extérieur, plutôt que de les créer à l'intérieur de l'objet lui-même.



Prenons un exemple concret. Imaginez que vous faites un gâteau. Au lieu de moudre vous-même la farine, de ramasser les œufs et de baratter le beurre (créer les dépendances en interne), vous allez simplement au magasin et achetez des ingrédients prêts (vous recevez les dépendances de l'extérieur). La DI fonctionne sur le même principe : vous « commandez » des composants prêts, sans les créer manuellement.



En Kotlin, la DI est particulièrement importante car le langage est activement utilisé pour créer des applications Android, des solutions serveur avec Ktor et des microservices. Sans DI, le code devient fortement couplé, difficile à tester et à maintenir. Avec la DI, vous obtenez :

  • Flexibilité — remplacer facilement une implémentation par une autre
  • Testabilité — possibilité d'utiliser des objets mock
  • Propreté du code — les classes ne savent pas comment leurs dépendances sont créées


Le problème sans injection de dépendances



Considérons une situation typique. Nous avons une classe UserService qui interagit avec une base de données. Sans DI, cela ressemble à ceci :



class UserService {    private val database = Database() // Couplage fort

fun getUser(id: Int): User? { return database.query("SELECT * FROM users WHERE id = $id") }}


Quels sont les problèmes ? Premièrement, UserService crée lui-même une instance de Database. Si nous voulons remplacer la vraie base de données par une base de test (par exemple, en mémoire), nous devons modifier le code à l'intérieur de la classe. Deuxièmement, les tests unitaires deviennent impossibles — nous ne pouvons pas utiliser une fausse base de données. Troisièmement, la classe viole le principe de responsabilité unique (SRP) : elle ne gère pas seulement les utilisateurs, mais aussi la création de la base de données.



Imaginez des dizaines de dépendances de ce type — le code se transforme en « spaghetti », où tout est lié à tout. C'est précisément pour résoudre ce problème que l'injection de dépendances existe.



Implémentation manuelle de l'injection de dépendances



La façon la plus simple d'injecter des dépendances est de les passer via le constructeur. C'est ce qu'on appelle l'injection par constructeur. Réécrivons notre exemple :



class UserService(private val database: Database) {    fun getUser(id: Int): User? {        return database.query("SELECT * FROM users WHERE id = $id")    }}

// Utilisation :val database = Database()val userService = UserService(database)


Maintenant, UserService ne sait pas comment Database est créée. Il reçoit simplement une instance prête. Nous pouvons facilement remplacer la base de données :



class FakeDatabase : Database() {    override fun query(sql: String): User? {        return User(1, "Utilisateur de test")    }}

// Dans les tests :val fakeDb = FakeDatabase()val userService = UserService(fakeDb)


Cette approche s'appelle DI manuelle. Pour les petits projets, elle est tout à fait suffisante. Vous créez simplement toutes les dépendances à un seul endroit (par exemple, dans main() ou dans une classe conteneur dédiée) et vous les transmettez là où elles sont nécessaires.



Cependant, la DI manuelle a un inconvénient : lorsque le projet s'agrandit, le nombre de dépendances devient énorme. Vous devez suivre manuellement l'ordre de création des objets et les transmettre à travers plusieurs niveaux. C'est là que les frameworks DI viennent à la rescousse.



Injection de dépendances avec Koin



Koin est un framework DI populaire pour Kotlin qui ne nécessite pas de génération de code

Blogs

Book Recommendations