Le constructeur qui ne raconte rien
Le constructeur compile, mais il oblige à mémoriser l'ordre des arguments. Les booléens ne racontent rien et une combinaison absurde reste possible.
Sans rouvrir la signature, que signifient true et false ? Et la mozzarella est-elle cohérente avec le booléen végane ? Les types seuls ne suffisent pas à raconter l'intention.
Les indications de l'IDE ne règlent pas tout
Nommer chaque choix
Démarrer
builder()crée un objet temporaire avec ses valeurs par défaut.Ajuster
Chaque méthode nomme un choix, modifie le constructeur progressif et retournethispour permettre le chaînage.Terminer
build()valide la configuration complète et crée l'objet final.
Le constructeur progressif et la pizza sont deux objets différents. Le premier est mutable et temporaire. La seconde copie ses données et devient le résultat utilisé par le programme.
Validation à l'exécution
Cheese contient aussi des fromages véganes, et build() refuse une pizza végane dont le fromage ne l'est pas. L'appel du début de la leçon, mozzarella puis vegan(), compile donc sans erreur, mais lève une IllegalStateException au moment de build(). La vérification est utile, mais elle arrive tard : à l'exécution.Factoriser une base fréquente
Un preset prépare une configuration fréquente puis rend le constructeur progressif, pas l'objet final.
houseStyle() retire la répétition, mais addTopping("olives") reste possible avant build(). Un preset peut aussi partir d'un autre preset : la variante sans gluten remplace seulement ce qui change.
Preset utile
- • Une base revient souvent.
- • Chaque appel doit encore pouvoir l'ajuster.
- • Le nom du preset exprime une intention métier.
Preset trompeur
- • Il construit immédiatement l'objet final.
- • Il cache une règle sans nom clair.
- • Il duplique les mêmes réglages qu'un autre preset.
Retirer l'opération dangereuse
Le constructeur progressif classique rend l'appel lisible, mais il expose toujours cheese(Cheese) après vegan() : l'appel incohérent compile et n'échoue qu'à l'exécution. Le Constructeur par étapes change la forme de l'API après ce choix précis.
vegan() change le type statique
L'expression ne renvoie plusBuilder, maisVeganBuilder.La branche conserve le vocabulaire utile
La croûte, les garnitures, la préparation séparée etbuild()restent disponibles. Le fromage passe par un enum limité aux choix véganes.La mauvaise opération disparaît
cheese(Cheese)n'existe pas sur le type retourné. Le compilateur refuse l'appel avant toute exécution.
Pragmatique, pas rigide
vegan().| Solution | Ce qu'elle garantit | Prix |
|---|---|---|
| Constructeur | Les types et l'ordre de la signature. | Arguments positionnels vite illisibles. |
| Constructeur progressif | Options nommées, défauts et validation dans build(). | Un objet et une API temporaires; l'invalide peut compiler. |
| Constructeur par étapes ciblé | Certaines opérations disparaissent selon la branche. | Types ou wrappers supplémentaires, API plus rigide. |
Bon cas
- • Beaucoup d'options facultatives.
- • Des arguments positionnels sont ambigus.
- • Une branche doit rendre certaines opérations impossibles.
Mauvais cas
- • Un objet stable possède deux champs évidents.
- • Aucune valeur par défaut ni validation n'existe.
- • La règle change si souvent que l'API typée devient un fardeau.
Vérifiez vos réflexes
Vérifiez vos réflexes
Une réponse par question. La correction apparaît tout de suite.
Encodez une règle dans l'API
Rendez l'appel invalide impossible
Écrivez d'abord. Une IA externe pourra ensuite relire votre travail. Son retour peut être faux. Vérifiez-le avec la leçon.
Brouillon enregistré sur cet appareil.
Voir le prompt qui sera copié
Vous corrigez le travail d'un étudiant qui prépare une remédiation Java 17. Évaluez d'abord son raisonnement, ses invariants et la cohérence de son brouillon. Un code incomplet mais bien expliqué mérite un retour utile. Signalez précisément les erreurs sans inventer d'exigences hors sujet.
Cette leçon porte sur Builder, preset et Step Builder pragmatique en Java. Vérifiez que vegan() change réellement le type statique, que la branche ne propose plus cheese(Cheese), mais conserve les opérations utiles et build(). Le preset doit être composable et ne doit pas construire immédiatement la Pizza. N'exigez pas une interface par champ. Acceptez un wrapper ou quelques interfaces ciblées. Contrôlez surtout la distinction entre erreur à l'exécution dans build() et appel impossible à compiler.
Travail demandé:
Le builder de Pizza laisse compiler cet appel, qui n'échoue qu'à l'exécution de build() :
Pizza.builder()
.vegan()
.cheese(Cheese.MOZZARELLA)
.build();
Refactorez uniquement cette branche.
1. vegan() doit retourner un petit type VeganBuilder.
2. VeganBuilder conserve crust(...), addTopping(...), preparedSeparately() et build().
3. Il expose veganCheese(VeganCheese), mais pas cheese(Cheese).
4. Ne transformez pas chaque champ en étape obligatoire.
5. Ajoutez un preset houseStyle() qui retourne un builder prérempli mais encore modifiable.
6. Donnez un appel valide et un appel invalide commenté qui échouerait à la compilation.
7. Expliquez la différence entre une validation dans build() et une garantie portée par le type retourné.
Commencez par poser au plus deux questions si une intention reste ambiguë. Donnez ensuite les points corrects, les problèmes précis et la plus petite prochaine étape. Ne fournissez une solution complète que si l'étudiant la demande explicitement.
Réponse de l'étudiant:
[aucune réponse collée]