Modèles de conception en Swift : des bases à la pratique
Les modèles de conception (Design Patterns) sont des solutions éprouvées pour des problèmes de développement courants. Dans le monde de Swift et de l'écosystème Apple (iOS/macOS), leur connaissance devient indispensable pour créer un code maintenable, testable et évolutif. Dans cet article, nous analyserons les modèles clés, en les divisant en trois catégories principales : les patrons de création, structurels et comportementaux. Chaque modèle sera illustré par un exemple fonctionnel en Swift.
Patrons de création : Singleton, Factory Method et Builder
Les patrons de création gèrent le processus de création d'objets, le rendant plus flexible et indépendant du code client.
Singleton (Singleton)
Garantit qu'une classe n'a qu'une seule instance et fournit un point d'accès global à celle-ci. Sous iOS, il est souvent utilisé pour gérer les sessions réseau, les bases de données (Core Data) ou les paramètres de l'application.
class NetworkManager { static let shared = NetworkManager() private init() {} func fetchData(from url: URL) { // Logique de requête print("Fetching data from \\(url)") }}
// UtilisationNetworkManager.shared.fetchData(from: URL(string: "https://example.com")!)Factory Method (Méthode de fabrique)
Définit une interface pour créer un objet, mais permet aux sous-classes de modifier le type d'objet créé. Idéal pour créer des composants d'interface utilisateur en fonction de la version iOS ou de la configuration.
protocol Button { func render()}
class iOSButton: Button { func render() { print("Rendering iOS button") }}
class macOSButton: Button { func render() { print("Rendering macOS button") }}
enum Platform { case iOS, macOS }
class ButtonFactory { static func createButton(for platform: Platform) -> Button { switch platform { case .iOS: return iOSButton() case .macOS: return macOSButton() } }}
// Utilisationlet button = ButtonFactory.createButton(for: .iOS)button.render()Builder (Constructeur)
Permet de créer des objets complexes étape par étape. Largement utilisé pour configurer des requêtes (URLRequest) ou des réglages d'interface utilisateur complexes.
class Pizza { var dough: String = "" var cheese: String = "" var toppings: [String] = []}
class PizzaBuilder { private var pizza = Pizza() func setDough(_ dough: String) -> PizzaBuilder { pizza.dough = dough return self } func setCheese(_ cheese: String) -> PizzaBuilder { pizza.cheese = cheese return self } func addTopping(_ topping: String) -> PizzaBuilder { pizza.toppings.append(topping) return self } func build() -> Pizza { return pizza }}
// Utilisationlet margherita = PizzaBuilder() .setDough("Thin") .setCheese("Mozzarella") .addTopping("Basil") .build()Patrons structurels : Adapter, Decorator et Facade
Les patrons structurels simplifient la conception en définissant des moyens de combiner des objets et des classes en structures plus grandes.
Adapter (Adaptateur)
Permet à des objets avec des interfaces incompatibles de fonctionner ensemble. Un exemple classique est l'intégration de bibliothèques tierces ou le travail avec du code hérité.
// Ancien protocoleprotocol OldPaymentSystem { func pay(amount: Double)}
// Nouveau protocoleprotocol NewPaymentSystem { func processPayment(amount: Double, currency: String)}
// Adaptateurclass PaymentAdapter: NewPaymentSystem { private let oldSystem: OldPaymentSystem init(oldSystem: OldPaymentSystem) { self.oldSystem = oldSystem } func processPayment(amount: Double, currency: String) { // Conversion de devise let convertedAmount = amount * 1.1 oldSy