Principes SOLID en Kotlin : théorie et pratique de A à Z

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

Principes SOLID en Kotlin : de la théorie à la pratique

\n\n

SOLID est l'acronyme de cinq principes fondamentaux de la programmation orientée objet, formulés par Robert Martin. Ces principes aident à créer un code flexible, maintenable et évolutif. Dans cet article, nous analyserons en détail chaque principe SOLID avec des exemples issus du développement réel en Kotlin.

\n\n

La compréhension de SOLID est cruciale pour tout développeur Kotlin, en particulier lorsqu'il travaille avec des frameworks comme Spring Boot ou Ktor. Ces principes sont à la base de l'architecture propre et des patrons de conception.

\n\n

1. Single Responsibility Principle (SRP) — Principe de responsabilité unique

\n\n

Essence : Chaque classe ne doit avoir qu'une seule raison de changer. Autrement dit, une classe doit être responsable d'une seule fonctionnalité.

\n\n

En Kotlin, ce principe est particulièrement important en raison du support du style fonctionnel. Considérons un mauvais exemple :

\n\n
// ❌ Violation du SRP : la classe s'occupe à la fois de la journalisation et du travail avec la BD\nclass UserService {\n    fun saveUser(user: User) {\n        // Journalisation\n        println("Saving user: ${user.name}")\n        // Logique métier\n        validateUser(user)\n        // Travail avec la BD\n        database.insert(user)\n    }\n}\n
\n\n

Corrigeons la situation en séparant les responsabilités :

\n\n
// ✅ Approche correcte : chaque responsabilité dans une classe séparée\nclass Logger {\n    fun log(message: String) = println("[LOG] $message")\n}\n\nclass UserValidator {\n    fun validate(user: User): Boolean = user.name.isNotBlank()\n}\n\nclass UserRepository {\n    fun save(user: User) { /* sauvegarde en BD */ }\n}\n\nclass UserService(\n    private val logger: Logger,\n    private val validator: UserValidator,\n    private val repository: UserRepository\n) {\n    fun saveUser(user: User) {\n        logger.log("Saving user: ${user.name}")\n        if (validator.validate(user)) {\n            repository.save(user)\n        }\n    }\n}\n
\n\n

2. Open-Closed Principle (OCP) — Principe d'ouverture/fermeture

\n\n

Essence : Les classes doivent être ouvertes à l'extension, mais fermées à la modification. De nouvelles fonctionnalités doivent être ajoutées par héritage ou composition, sans modifier le code existant.

\n\n

En Kotlin, les classes sealed et les interfaces sont parfaites pour implémenter l'OCP :

\n\n
// ❌ Violation de l'OCP : lors de l'ajout d'un nouveau type de figure, il faut modifier la classe\nclass AreaCalculator {\n    fun calculate(shape: Any): Double = when (shape) {\n        is Circle -> 3.14 * shape.radius * shape.radius\n        is Rectangle -> shape.width * shape.height\n        else -> throw IllegalArgumentException()\n    }\n}\n
\n\n

Implémentation correcte utilisant le polymorphisme :

\n\n
// ✅ Approche correcte : de nouvelles figures sont ajoutées sans modifier le code existant\ninterface Shape {\n    fun area(): Double\n}\n\nclass Circle(val radius: Double) : Shape {\n    override fun area() = Math.PI * radius * radius\n}\n\nclass Rectangle(val width: Double, val height: Double) : Shape {\n    override fun area() = width * height\n}\n\n// On peut maintenant ajouter un triangle sans modifier AreaCalculator\nclass Triangle(val base: Double, val height: Double) : Shape {\n    override fun area() = 0.5 * base * height\n}\n\nclass AreaCalculator {\n    fun calculate(shape: Shape) = shape.area()\n}\n
\n\n

3. Liskov Substitution Principle (LSP) — Principe de substitution de Barbara Liskov

\n\n

Essence : Les objets de la classe de base doivent pouvoir être remplacés par des objets des classes dérivées sans altérer le fonctionnement du programme. Une sous-classe ne doit pas affaiblir les préconditions ni renforcer les postconditions.

\n\n

Considérons l'exemple classique du rectangle et du carré :

\n\n
// ❌ Violation du LSP : le carré ne peut pas remplacer le rectangle\nopen class Rectangle(\n    open var width: Int,\n    open var height: Int\n) {\n    fun area() = width * height\n}\n\nclass Square(sid                

Blogs

Book Recommendations