SOLID : principes, 5 règles POO et application dans le développement

Auteur : IT Sectr Publié le : 2026-05-11 Temps de lecture : 10 min

SOLID — cinq principes de programmation orientée objet formulés par Robert C. Martin (Uncle Bob) au début des années 2000. Selon DigitalOcean, 2024, SOLID signifie Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation et Dependency Inversion. Ces principes constituent le fondement de Clean Architecture et sont appliqués dans le développement Android (MVP, MVVM, Clean Architecture) et iOS (VIPER, TCA).

Points clés

  • SOLID — acronyme de cinq principes POO : SRP, OCP, LSP, ISP, DIP, formulés par Robert C. Martin pour créer un code flexible et maintenable.
  • SRP (Single Responsibility) — chaque classe a une seule raison de changer, une responsabilité par module.
  • OCP (Open-Closed) — les classes sont ouvertes à l’extension mais fermées à la modification, implémenté par héritage et polymorphisme.
  • LSP (Liskov Substitution) — les objets des sous-classes doivent remplacer les objets de la classe de base sans altérer la correction du programme.
  • ISP (Interface Segregation) — les clients ne doivent pas dépendre d’interfaces qu’ils n’utilisent pas, les interfaces doivent être étroites et spécifiques.
  • DIP (Dependency Inversion) — les modules de haut niveau ne dépendent pas des modules de bas niveau, tous deux dépendent d’abstractions.

Qu’est-ce que SOLID ? Aperçu des cinq principes

SOLID — un acronyme mnémonique représentant cinq principes de conception orientée objet. Le terme a été introduit par Robert C. Martin dans l’article « Design Principles and Design Patterns » (2000) et popularisé plus tard dans le livre « Agile Software Development : Principles, Patterns, and Practices » (2002). SOLID n’est pas un framework ni une bibliothèque — c’est un ensemble de pratiques qui rendent le code moins couplé, plus testable et plus facile à modifier.

Selon Clean Coder Blog, 2014, chaque principe SOLID résout un problème de conception spécifique : SRP combat les classes God, OCP empêche les modifications en cascade, LSP protège contre les héritages incorrects, ISP évite les interfaces épaisses et DIP réduit le couplage fort. Ensemble, ils forment le fondement de Clean Architecture, utilisée dans les projets Android avec MVP, MVVM et MVI.

SRP : Principe de Responsabilité Unique

Single Responsibility Principle (SRP) — principe de responsabilité unique. La formulation : « Une classe ne devrait avoir qu’une seule raison de changer. » Cela signifie que chaque module ou classe est responsable d’exactement une fonctionnalité ou une entité du domaine. Si une classe gère à la fois les utilisateurs et l’envoi d’e-mails — elle a deux raisons de changer, violant SRP.

Selon Robert C. Martin, 2002, SRP est le principe le plus important et simultanément le plus violé. Dans le développement mobile, SRP est souvent violé dans Activity/Fragment en combinant logique UI, navigation, réseau et logique métier. La solution consiste à extraire chaque couche dans une classe séparée : ViewModel pour la logique UI, Repository pour les données, NavController pour la navigation.

Exemple SRP : Décomposition de UserManager

Considérez la classe UserManager, qui charge un profil, sauvegarde les paramètres et envoie des e-mails. Ce sont trois responsabilités distinctes, chacune devant être extraite dans une classe séparée : UserProfileRepository (chargement), UserSettingsStorage (sauvegarde) et EmailService (envoi). Le code client (ViewModel) utilise les trois via Dependency Injection, et chaque classe est facilement testée isolément et modifiée sans affecter les autres.

kotlin
// ❌ Violation SRP : Activity connaît le réseau, la BD et l’UI
class ProfileActivity : AppCompatActivity() {
    fun loadProfile() {
        api.getUser() // Appel réseau
        db.saveUser()    // Opération BD
        updateUI()         // Mise à jour UI
    }
}

// ✅ SRP respecté : les couches sont séparées
class ProfileViewModel : ViewModel() {
    private val repo = UserRepository()
    fun loadProfile() { repo.getUser() }
}

Signes de violation de SRP : une classe de plus de 200 lignes, des méthodes de différents domaines, des changements fréquents pour différentes raisons. Pour le développement Android, la règle est simple : Activity gère uniquement le cycle de vie de l’écran, ViewModel gère l’état UI, Repository gère les sources de données.

SRP et Architecture Microservices

Le principe SRP s’applique non seulement aux classes mais aussi à l’architecture au niveau service. Chaque microservice gère une entité du domaine : UserService — uniquement les utilisateurs, PaymentService — uniquement les paiements, NotificationService — uniquement les notifications. Cela permet de scaler, déployer et tester les services indépendamment. Dans les applications mobiles, SRP au niveau microservice se manifeste par la séparation des clients API par domaine.

OCP : Principe Ouvert/Fermé

Open-Closed Principle (OCP) — les classes doivent être ouvertes à l’extension (un nouveau comportement peut être ajouté) et fermées à la modification (le code existant n’est pas modifié). Ceci est atteint via le polymorphisme, les classes abstraites et les interfaces. Au lieu d’ajouter des if-else à une méthode existante, une nouvelle implémentation d’interface est créée.

Selon Clean Coder Blog, 2014, OCP fonctionne le mieux avec le pattern Strategy. Par exemple, si une application prend en charge différents modes de paiement (Google Pay, Apple Pay, PayPal), il n’est pas nécessaire d’ajouter un switch-case au processeur de paiement. Chaque mode de paiement implémente une interface commune PaymentGateway, et un nouveau système de paiement est ajouté comme une nouvelle classe sans modifier les existantes.

kotlin
// ✅ OCP : ouvert à l’extension, fermé à la modification
interface PaymentGateway {
    fun processPayment(amount: Double): Boolean
}

class GooglePayGateway : PaymentGateway {
    override fun processPayment(amount: Double) = true
}

// Nouveau système de paiement — sans modifier le code existant
class ApplePayGateway : PaymentGateway {
    override fun processPayment(amount: Double) = true
}

LSP : Principe de Substitution de Liskov

Liskov Substitution Principle (LSP) — principe de substitution de Barbara Liskov. Si S est un sous-type de T, alors les objets de type T peuvent être remplacés par des objets de type S sans modifier les propriétés du programme. Formellement : une fonction utilisant une classe de base doit fonctionner correctement avec n’importe laquelle de ses sous-classes. Si une sous-classe lance une exception là où la classe de base n’en lance pas — LSP est violé.

Selon Robert C. Martin, 2002, LSP est le principe SOLID le plus difficile à comprendre. L’exemple classique de violation est la classe Square héritant de Rectangle. Si setWidth sur Square définit à la fois la largeur et la hauteur, le code client s’attendant au comportement de Rectangle obtient un résultat inattendu. Dans le développement mobile, LSP est souvent violé lors de l’héritage de ViewModel — lorsqu’une ViewModel enfant ajoute des dépendances obligatoires.

kotlin
// ❌ Violation LSP : Square casse le comportement de Rectangle
open class Rectangle(open var width: Int, open var height: Int)

class Square(side: Int) : Rectangle(side, side) {
    override var width
        get() = super.width
        set(value) { super.setBoth(value, value) }
}

ISP : Principe de Ségrégation des Interfaces

Interface Segregation Principle (ISP) — les clients ne doivent pas dépendre d’interfaces qu’ils n’utilisent pas. Au lieu d’une seule interface « grasse », créez plusieurs interfaces étroites et spécialisées. Si une classe implémente une interface mais que certaines méthodes lancent UnsupportedOperationException ou restent vides — c’est un signe clair de violation d’ISP.

Selon DigitalOcean, 2024, ISP est particulièrement pertinent dans le développement mobile lors de la conception de ViewModel et Repository. Au lieu d’une seule interface UserRepository avec toutes les méthodes CRUD, il est préférable de créer QueryUserRepository (lecture seule) et CommandUserRepository (écriture). Ainsi, un client en lecture seule (élément UI) dépend uniquement de l’interface Query et ne connaît rien des méthodes d’écriture.

kotlin
// ❌ Interface épaisse — le client est obligé d’implémenter des méthodes inutiles
interface UserOperations {
    fun getUser(id: String): User
    fun saveUser(user: User)
    fun deleteUser(id: String)
    fun exportUsers(): File
}

// ✅ ISP : interfaces ségréguées
interface UserReader { fun getUser(id: String): User }
interface UserWriter { fun saveUser(user: User) }
interface UserDeleter { fun deleteUser(id: String) }

DIP : Principe d’Inversion des Dépendances

Dependency Inversion Principle (DIP) — les modules de haut niveau ne doivent pas dépendre des modules de bas niveau. Les deux doivent dépendre d’abstractions (interfaces). Les abstractions ne doivent pas dépendre des détails — les détails doivent dépendre des abstractions. Ce n’est pas « Dependency Injection » (DI), bien que DI soit un moyen courant d’implémenter DIP.

Selon Robert C. Martin, 2019, DIP est le fondement de Clean Architecture. ViewModel (haut niveau) ne doit pas créer directement une instance de RetrofitApi (détail). Au lieu de cela, ViewModel dépend d’une interface UserRepository, et l’implémentation concrète UserRepositoryImpl avec Retrofit est passée via le constructeur. Dans Android, DIP est implémenté via Hilt/Dagger ou Koin : toutes les dépendances sont fournies via le conteneur DI.

kotlin
// ✅ DIP : Module dépend de l’abstraction, pas des détails
class UserRepositoryImpl(
    private val api: UserApi,   // Dépend de l’interface
    private val db: UserDao     // Dépend de l’interface
) : UserRepository {

    override suspend fun getUser(id: String): User {
        return api.fetchUser(id)
    }
}

// Hilt DI : les détails sont connectés via le module DI
@Module
object NetworkModule {
    @Provides
    fun provideUserApi(retrofit: Retrofit): UserApi =
        retrofit.create(UserApi::class.java)
}

Application de SOLID dans le développement mobile

SOLID dans le développement mobile est appliqué à tous les niveaux : de l’architecture de l’application aux classes individuelles. Dans les projets Android, Clean Architecture divise le code en trois couches : domain (logique métier — indépendante des frameworks), data (référentiels, API, BD) et presentation (UI, ViewModel). La couche domain utilise les principes SOLID : cas d’utilisation (SRP), interfaces de référentiel (DIP), classes d’entité (OCP + LSP).

Selon Android Developers Guide, 2025, SRP dans Android se manifeste dans la séparation de ViewModel, Repository et Mapper. OCP — lors de l’ajout de nouvelles sources de données via l’interface DataSource. LSP — dans le traitement uniforme de Result à travers différents référentiels. ISP — dans l’approche CQRS (séparation des référentiels Read/Write). DIP — via Hilt/Koin pour l’injection de dépendances.

PrincipeProblème sans luiSolution dans un projet mobile
SRPActivity de 1000+ lignesViewModel + UseCase + Repository
OCPswitch-case par type de paiementStrategy : interface PaymentGateway
LSPErreur lors du remplacement de BaseViewModelVérifier le contrat des sous-classes
ISPUnsupportedOperationExceptionSéparation Reader / Writer
DIPViewModel crée Retrofit manuellementConteneur DI Hilt / Koin

Erreurs courantes lors de l’application de SOLID

Erreurs SOLID sont le plus souvent liées à une surcomplexification excessive du code. La première — suivre les principes littéralement sans tenir compte du contexte. Diviser une classe UserService en 10 interfaces et 15 classes juste pour un ISP « propre » est du sur-ingénierie. SOLID est un outil, pas un objectif. La deuxième erreur — confondre SRP avec « une méthode = une responsabilité ». Une classe peut avoir plusieurs méthodes si elles appartiennent toutes au même domaine de responsabilité.

Selon Simple Thread, 2024, la troisième erreur — ignorer LSP lors de l’héritage de ViewModel dans Android. Si la ViewModel de base attend LiveData mais que l’enfant utilise StateFlow — le code client abonné à LiveData ne recevra pas les mises à jour. La quatrième — violer DIP pour les tests : RepositoryImpl crée directement une instance OkHttpClient, rendant les tests unitaires impossibles.

La règle d’or : appliquez SOLID quand il résout un vrai problème (changements fréquents, difficulté de test, duplication). Pour des écrans CRUD simples, le respect strict des cinq principes est excessif. Pour la logique métier, les calculs financiers et les interactions API, SOLID est essentiel.

Lien entre SOLID et Clean Architecture

Clean Architecture (Robert C. Martin, 2012) — application directe de SOLID au niveau des couches de l’application. SRP définit les limites des cas d’utilisation (chaque cas d’utilisation — une classe). OCP est implémenté via les interfaces de référentiel (Data Layer peut changer sans modifier Domain). ISP fournit la séparation du cas d’utilisation en limites d’entrée/sortie. DIP — direction des dépendances vers l’intérieur de la couche Domain. LSP garantit que toute implémentation de référentiel est remplaçable sans casser les cas d’utilisation.

Questions fréquentes

Qu’est-ce que SOLID en termes simples ?

SOLID — cinq règles pour écrire du code facile à modifier, tester et comprendre. Chaque lettre est un principe : n’écrivez pas de grandes classes (SRP), ne modifiez pas le code existant — ajoutez du nouveau (OCP), ne cassez pas le comportement des sous-classes (LSP) et autres.

Quel principe SOLID est le plus important ?

SRP (Single Responsibility) est considéré comme le plus important car sa violation mène à des classes God — des classes énormes difficiles à tester et à modifier. Cependant, sans DIP (Dependency Inversion), le code reste fortement couplé, ce qui est également critique.

SOLID est-il obligatoire pour le développement mobile ?

Pas obligatoire, mais fortement recommandé pour les projets commerciaux à long cycle de vie. Pour les applications simples (un écran, pas de logique métier), SOLID peut être excessif. Pour les projets de 50+ écrans et 3+ développeurs, SOLID est le minimum nécessaire.

Que se passe-t-il si on ne suit pas SOLID ?

Conséquences : les classes deviennent « grasses » (1000+ lignes), un changement à un endroit en casse trois autres, les tests unitaires deviennent impossibles, l’ajout d’une nouvelle fonctionnalité prend des semaines au lieu de jours. Avec le temps, le code devient une « Big Ball of Mud » — emmêlé et fragile.

Comment vérifier si SOLID est suivi dans un projet ?

Signes de conformité : chaque classe fait moins de 200 lignes, modifier une fonctionnalité n’affecte pas 5+ fichiers, les tests peuvent être écrits sans simuler 10 dépendances, un nouveau développeur comprend la structure en un jour. Des outils comme SonarQube et detekt aident à identifier les violations de SRP et DIP.

Résumé

  • SOLID — cinq principes POO (SRP, OCP, LSP, ISP, DIP) pour créer un code flexible et maintenable
  • SRP — chaque entité est responsable d’une tâche, résout le problème des classes God
  • OCP — extension via polymorphisme, pas de modification du code existant
  • LSP — les sous-classes ne doivent pas casser le comportement de la classe de base
  • ISP — des interfaces étroites au lieu de « couteaux suisses » universels
  • DIP — dépendance des abstractions, injection via Hilt/Koin dans Android
  • SOLID est essentiel pour Clean Architecture et les projets mobiles commerciaux

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi