Modèles de conception créative dans Kotlin: Builder

1. Introduction

Dans cet article rapide, nous verrons comment implémenter le modèle de conception Builder dans Kotlin.

2. Modèle de constructeur

Le modèle Builder est celui que les gens utilisent souvent mais créent rarement eux-mêmes.

C'est génial de gérer la construction d'objets qui peuvent contenir beaucoup de paramètres et lorsque nous voulons rendre l'objet immuable une fois que nous avons fini de le construire.

Pour en savoir plus, consultez notre didacticiel sur les modèles de conception créative ici.

3. Mise en œuvre

Kotlin fournit de nombreuses fonctionnalités utiles telles que les paramètres nommés et par défaut, apply () et la classe de données qui évitent l'utilisation de l'implémentation de modèle classique de Builder.

Pour cette raison, nous verrons d'abord une implémentation classique de style Java, puis une forme courte de style Kotlin.

3.1. Implémentation de style Java

Commençons par créer une classe - FoodOrder - qui contient des champs en lecture seule puisque nous ne voulons pas que les objets externes y accèdent directement:

class FoodOrder private constructor(builder: FoodOrder.Builder) { val bread: String? val condiments: String? val meat: String? val fish: String? init { this.bread = builder.bread this.condiments = builder.condiments this.meat = builder.meat this.fish = builder.fish } class Builder { // builder code } }

Notez que le constructeur est privé afin que seule la classe Builder imbriquée puisse y accéder.

Passons maintenant à la création de la classe imbriquée qui sera utilisée pour construire des objets:

class Builder { var bread: String? = null private set var condiments: String? = null private set var meat: String? = null private set var fish: String? = null private set fun bread(bread: String) = apply { this.bread = bread } fun condiments(condiments: String) = apply { this.condiments = condiments } fun meat(meat: String) = apply { this.meat = meat } fun fish(fish: String) = apply { this.fish = fish } fun build() = FoodOrder(this) } 

Comme nous le voyons, notre Builder a les mêmes champs que la classe externe. Pour chaque champ externe, nous avons une méthode de setter correspondante.

Au cas où nous aurions un ou plusieurs champs obligatoires, au lieu d'utiliser des méthodes setter, faisons en sorte qu'un constructeur les définisse.

Notez que nous utilisons la fonction apply afin de prendre en charge l'approche de conception fluide.

Enfin, avec la méthode build , nous appelons le constructeur FoodOrder .

3.2. Implémentation de style Kotlin

Afin de tirer pleinement parti de Kotlin, nous devons revoir certaines des meilleures pratiques auxquelles nous nous sommes habitués en Java. Beaucoup d'entre eux peuvent être remplacés par de meilleures alternatives.

Voyons comment nous pouvons écrire du code Kotlin idiomatique:

class FoodOrder private constructor( val bread: String?, val condiments: String?, val meat: String?, val fish: String?) { data class Builder( var bread: String? = null, var condiments: String? = null, var meat: String? = null, var fish: String? = null) { fun bread(bread: String) = apply { this.bread = bread } fun condiments(condiments: String) = apply { this.condiments = condiments } fun meat(meat: String) = apply { this.meat = meat } fun fish(fish: String) = apply { this.fish = fish } fun build() = FoodOrder(bread, condiments, meat, fish) } }

Kotlin est livré avec des paramètres nommés et par défaut qui aident à minimiser le nombre de surcharges et à améliorer la lisibilité de l'appel de la fonction.

Nous pouvons également profiter de la structure de classe de données de Kotlin que nous explorons plus en détail dans un autre tutoriel ici.

Enfin, ainsi que dans l'implémentation de style Java, apply () est utile pour implémenter des setters fluents.

4. Exemple d'utilisation

En bref, voyons comment créer des objets FoodOrder à l' aide de ces implémentations de modèles Builder:

val foodOrder = FoodOrder.Builder() .bread("white bread") .meat("bacon") .condiments("olive oil") .build() 

5. Conclusion

Le modèle Builder résout un problème très courant dans la programmation orientée objet de la manière de créer de manière flexible un objet immuable sans écrire de nombreux constructeurs.

Lors de l'examen d'un constructeur, nous devons nous concentrer sur la complexité ou non de la construction. Si nous avons des modèles de construction trop simples, l'effort de création de notre objet de construction flexible peut dépasser de loin l'avantage.

Comme toujours, le code est disponible sur Github.