Sobes.tech
Middle

Quels modèles de conception peuvent être utilisés dans le langage Kotlin?

sobes.tech IA

Réponse de l'IA

En Kotlin, les modèles suivants sont souvent utilisés:

  • Singleton: Facile à implémenter via object.
    object MonSingleton {
        fun faireQuelqueChose() {
            // ...
        }
    }
    
  • Factory Method: Utilise une fonction abstraite dans la superclasse ou interface, que les sous-classes implémentent pour créer des objets.
    interface Produit {
        fun operation()
    }
    
    class ProduitConcretA : Produit {
        override fun operation() {
            // ...
        }
    }
    
    abstract class Createur {
        abstract fun methodeFabrica(): Produit
    
        fun uneOperation(): Produit {
            val produit = methodeFabrica()
            // ...
            return produit
        }
    }
    
    class CreateurConcretA : Createur() {
        override fun methodeFabrica(): Produit {
            return ProduitConcretA()
        }
    }
    
  • Abstract Factory: Groupe de fabriques pour créer des familles d'objets liés.
    interface ProduitAbstractA {
        fun fonctionUtilA()
    }
    
    interface ProduitAbstractB {
        fun fonctionUtilB()
        fun autreFonctionUtilB(collaborateur: ProduitAbstractA)
    }
    
    interface FabriqueAbstracte {
        fun creerProduitA(): ProduitAbstractA
        fun creerProduitB(): ProduitAbstractB
    }
    
    // Implémentations concrètes des produits et fabriques...
    
  • Builder: Facilite la création d'objets complexes étape par étape.
    class Pizza private constructor(
        val croûte: String,
        val sauce: String?,
        val garnitures: List<String>
    ) {
        data class Builder(
            var croûte: String = "fine",
            var sauce: String? = null,
            val garnitures: MutableList<String> = mutableListOf()
        ) {
            fun avecCroûte(croûte: String) = apply { this.croûte = croûte }
            fun avecSauce(sauce: String) = apply { this.sauce = sauce }
            fun ajouterGarniture(garniture: String) = apply { this.garnitures.add(garniture) }
            fun construire() = Pizza(croûte, sauce, garnitures)
        }
    }
    
    fun main() {
        val pizza = Pizza.Builder()
            .avecCroûte("épaisse")
            .avecSauce("tomate")
            .ajouterGarniture("pepperoni")
            .ajouterGarniture("champignons")
            .construire()
        // ... utiliser la pizza
    }
    
  • Adapter: Permet à des objets avec des interfaces incompatibles de travailler ensemble.
    open class Adapté {
        fun operationSpecifique() {
            // ...
        }
    }
    
    interface Cible {
        fun operation()
    }
    
    class Adaptateur(private val adapte: Adapté) : Cible {
        override fun operation() {
            adapte.operationSpecifique()
        }
    }
    
  • Decorator: Ajoute de nouvelles fonctionnalités aux objets existants sans changer leur structure. Les extensions et la délégation en Kotlin facilitent cela.
    interface SourceDeDonnees {
        fun lireDonnees(): String
        fun ecrireDonnees(donnees: String)
    }
    
    class SourceDeDonneesFichier(private val nomFichier: String) : SourceDeDonnees {
        override fun lireDonnees(): String {
            // Lecture du fichier
            return ""
        }
    
        override fun ecrireDonnees(donnees: String) {
            // Écriture dans le fichier
        }
    }
    
    class DecorateurChiffrement(private val source: SourceDeDonnees) : SourceDeDonnees by source {
        override fun lireDonnees(): String {
            // Déchiffrer les données
            val donnees = source.lireDonnees()
            return donnees // données déchiffrées
        }
    
        override fun ecrireDonnees(donnees: String) {
            // Chiffrer les données
            source.ecrireDonnees(donnees) // données chiffrées
        }
    }
    
  • Observer: Définit la dépendance "un à plusieurs". Les Flow de coroutines et les propriétés déléguées de Kotlin peuvent être utilisés pour l'implémentation.
    // Implémentation simple sans Flow
    interface Observateur {
        fun mettreAJour(message: String)
    }
    
    class Sujet {
        private val observateurs = mutableListOf<Observateur>()
    
        fun attacher(observateur: Observateur) {
            observateurs.add(observateur)
        }
    
        fun detacher(observateur: Observateur) {
            observateurs.remove(observateur)
        }
    
        fun notifierObservateurs(message: String) {
            observateurs.forEach { it.mettreAJour(message) }
        }
    }
    
  • Strategy: Définit une famille d'algorithmes, les encapsule et les rend interchangeables.
    interface StrategieDePaiement {
        fun payer(montant: Double)
    }
    
    class PayerParCarteDeCredit(private val numeroCarte: String) : StrategieDePaiement {
        override fun payer(montant: Double) {
            println("Paiement de $montant avec Carte de Crédit $numeroCarte")
        }
    }
    
    class PayerParPayPal(private val email: String) : StrategieDePaiement {
        override fun payer(montant: Double) {
            println("Paiement de $montant avec PayPal $email")
        }
    }
    
    class Commande(private val strategie: StrategieDePaiement) {
        fun traiterCommande(montant: Double) {
            // ... traitement de la commande
            strategie.payer(montant)
        }
    }
    
  • State: Permet à un objet de changer son comportement en fonction de l'état interne. Les classes scellées et les expressions when simplifient sa mise en œuvre.
    sealed class Etat {
        object Inactif : Etat()
        object Chargement : Etat()
        data class Erreur(val message: String) : Etat()
        data class Succès(val data: Any) : Etat()
    }
    
    class Contexte {
        var etat: Etat = Etat.Inactif
    
        fun gererEvenement() {
            when (etat) {
                Etat.Inactif -> {
                    println("Gestion de l'événement en état Inactif")
                    etat = Etat.Chargement
                }
                Etat.Chargement -> {
                    println("Gestion de l'événement en état Chargement, ignore.")
                }
                is Etat.Erreur -> {
                    println("Gestion de l'événement en état Erreur: ${etat.message}")
                    // Possibilité de transition vers un autre état
                }
                is Etat.Succès -> {
                    println("Gestion de l'événement en état Succès: ${etat.data}")
                    // Possibilité de transition vers un autre état
                }
            }
        }
    }
    
  • Repository: Abstrait la logique d'accès aux données depuis la logique métier.

De nombreux autres modèles, tels que Facade, Proxy, Command, Iterator, Template Method et Visitor, sont également applicables en Kotlin. Les caractéristiques du langage telles que les extensions, la délégation, les data classes et les classes scellées rendent souvent l'implémentation des modèles plus idiomatique et concise.