Introduction : Pourquoi SOLID est le fondement d’un code Swift de qualité
Chaque développeur iOS/macOS rencontre tôt ou tard une situation où le code devient « spaghetti » : des modifications à un endroit cassent toute l’application, et les tests deviennent un cauchemar. C’est là que les principes SOLID viennent à la rescousse — cinq règles fondamentales de conception orientée objet, formulées par Robert Martin.
Dans cet article, nous allons décomposer chaque principe SOLID avec des exemples en Swift, montrer comment leur violation entraîne des problèmes, et fournir des solutions prêtes à l’emploi. Vous apprendrez à écrire un code facile à maintenir, à étendre et à tester.
1. Single Responsibility Principle (SRP) — Principe de responsabilité unique
Théorie
SRP stipule : une classe ne doit avoir qu’une seule raison de changer. Autrement dit, chaque classe est responsable d’exactement une fonctionnalité.
Violation du SRP (mauvais code)
class UserManager { func createUser(name: String, email: String) { // Création de l’utilisateur saveToDatabase(user: User(name: name, email: email)) sendWelcomeEmail(to: email) logEvent("User created: \\(name)") } private func saveToDatabase(user: User) { /* ... */ } private func sendWelcomeEmail(to email: String) { /* ... */ } private func logEvent(_ message: String) { /* ... */ }}Ici, UserManager est responsable de la création, de la sauvegarde, de l’envoi d’e-mails et de la journalisation — quatre raisons de changer.
Correction (bon code)
class UserService { private let repository: UserRepository private let emailService: EmailService private let logger: Logger init(repository: UserRepository, emailService: EmailService, logger: Logger) { self.repository = repository self.emailService = emailService self.logger = logger } func createUser(name: String, email: String) { let user = User(name: name, email: email) repository.save(user) emailService.sendWelcome(to: email) logger.log("User created: \\(name)") }}
class UserRepository { func save(_ user: User) { /* seulement la sauvegarde */ }}class EmailService { func sendWelcome(to email: String) { /* seulement l’envoi */ }}class Logger { func log(_ message: String) { /* seulement la journalisation */ }}Maintenant, chaque classe a une seule responsabilité, ce qui facilite les tests et la maintenance.
2. Open/Closed Principle (OCP) — Principe d’ouverture/fermeture
Théorie
Les classes doivent être ouvertes à l’extension, mais fermées à la modification. On ajoute de nouvelles fonctionnalités via l’héritage ou les protocoles, sans toucher au code existant.
Violation de l’OCP
class PaymentProcessor { func process(payment: Any, type: String) { if type == "card" { // Traitement par carte } else if type == "paypal" { // Traitement PayPal } // En ajoutant un nouveau type — on modifie cette classe }}Correction via les protocoles
protocol PaymentMethod { func process(amount: Double)}
class CardPayment: PaymentMethod { func process(amount: Double) { /* traitement par carte */ }}
class PayPalPayment: PaymentMethod { func process(amount: Double) { /* traitement PayPal */ }}
class PaymentProcessor { func process(payment: PaymentMethod, amount: Double) { payment.process(amount: amount) }}
// Ajout d’un nouveau type sans modifier le code existantclass ApplePayPayment: PaymentMethod { func process(amount: Double) { /* traitement Apple Pay */ }}Maintenant, pour ajouter un nouveau moyen de paiement, il suffit de créer une nouvelle classe implémentant le protocole PaymentMethod.