Introduction : Pourquoi SOLID est important en Kotlin ?
SOLID est un acronyme de cinq principes fondamentaux de la programmation orientée objet, formulés par Robert Martin. Dans le contexte de Kotlin, un langage multiplateforme moderne, ces principes prennent une importance particulière. Kotlin combine à la fois la POO et les capacités fonctionnelles, ce qui permet d'écrire un code plus flexible et maintenable. Le respect des principes SOLID aide les développeurs à créer des systèmes faciles à mettre à l'échelle, à tester et à maintenir.
Dans cet article, nous analyserons chacun des cinq principes avec des exemples concrets en Kotlin, de la théorie à la mise en œuvre pratique. Vous apprendrez à éviter les antipatterns typiques et à rendre votre code plus propre.
1. Single Responsibility Principle (SRP) — Principe de responsabilité unique
Théorie : Chaque classe doit avoir une seule raison de changer. En d'autres termes, une classe doit être responsable d'une seule fonctionnalité ou tâche.
Pratique en Kotlin : Les développeurs violent souvent le SRP en plaçant dans une seule classe la logique de traitement des données, la validation et le travail avec des services externes.
Exemple de violation :
class UserManager { fun saveUser(user: User) { // Sauvegarde dans la base de données println("User saved to DB") }
fun sendEmail(user: User, message: String) { // Envoi d'email println("Email sent to ${user.email}") }
fun validateUser(user: User): Boolean { // Validation des données return user.name.isNotEmpty() }}Ici, UserManager est responsable de la sauvegarde, de l'envoi d'email et de la validation. Si la logique d'envoi d'email change, il faudra modifier cette classe, ce qui pourrait casser la sauvegarde des données.
Version corrigée avec le SRP :
class UserRepository { fun save(user: User) { println("User saved to DB") }}
class EmailService { fun send(user: User, message: String) { println("Email sent to ${user.email}") }}
class UserValidator { fun validate(user: User): Boolean { return user.name.isNotEmpty() }}Maintenant, chaque classe a une responsabilité unique, ce qui simplifie les tests et la modification du code.
2. Open/Closed Principle (OCP) — Principe d'ouverture/fermeture
Théorie : Les entités logicielles (classes, modules, fonctions) doivent être ouvertes à l'extension, mais fermées à la modification. Cela signifie que vous devez pouvoir ajouter un nouveau comportement sans modifier le code existant.
Pratique en Kotlin : Utilisez des abstractions (interfaces ou classes abstraites) et le polymorphisme. En Kotlin, les sealed class et les expressions when sont parfaitement adaptées pour cela.
Exemple de violation :
class AreaCalculator { fun calculate(shape: Any): Double { return when (shape) { is Circle -> Math.PI * shape.radius * shape.radius is Square -> shape.side * shape.side else -> throw IllegalArgumentException("Unknown shape") } }}Pour ajouter une nouvelle forme (par exemple, Triangle), il faudrait modifier la méthode calculate.
Version corrigée avec l'OCP :
interface Shape { fun area(): Double}
class Circle(private val radius: Double) : Shape { override fun area() = Math.PI * radius * radius}
class Square(private val side: Double) : Shape { override fun area() = side * side}
class Triangle(private val base: Double, private val height: Double) : Shape { override fun area() = 0.5 * base * height}
class AreaCalculator { fun calculate(shape: Shape) = shape.area()}Maintenant, pour ajouter une nouvelle forme, il suffit de créer une nouvelle classe implémentant l'inter