Création Flexible d'Objets avec le Pattern Builder en JavaScript
Vous avez une fonction qui crée des objets utilisateur. Elle commence avec trois paramètres, puis passe à cinq, puis sept. La moitié d’entre eux sont optionnels. Les appelants doivent se souvenir de l’ordre exact, et une seule erreur de position produit silencieusement un objet défectueux. C’est le problème que résout le Pattern Builder en JavaScript.
Points Clés
- Le Pattern Builder construit des objets étape par étape en utilisant des méthodes setter chaînées et un appel final
build(), remplaçant les listes d’arguments positionnels sujettes aux erreurs. - Une API fluide, où chaque setter retourne
this, rend le site d’appel auto-documenté et indépendant de l’ordre. - Réservez ce pattern aux objets comportant de nombreux paramètres optionnels, une application de champs obligatoires ou des règles de validation. Pour les cas plus simples, utilisez des littéraux d’objets ou des fonctions factory.
- La méthode
build()est l’unique endroit pour valider les champs obligatoires et retourner un objet propre et figé, distinct du builder lui-même.
Qu’est-ce que le Pattern Builder en JavaScript ?
Le Pattern Builder est un patron de conception créationnel qui construit des objets étape par étape au lieu de tout créer d’un coup. Plutôt que de passer chaque valeur dans un seul appel de constructeur, vous chaînez des méthodes setter et finalisez la création avec une étape build() qui valide et retourne l’objet complété.
Ce n’est pas une solution universelle. Pour des objets simples avec deux ou trois champs bien définis, un simple littéral d’objet ou une fonction factory est plus propre. Le Pattern Builder trouve sa place lorsque la création d’objet implique :
- De nombreux paramètres optionnels dont l’ordre n’a pas d’importance
- Des règles de validation qui doivent s’exécuter avant l’utilisation de l’objet
- Des champs obligatoires qui doivent être appliqués au moment de la création
- Une construction en plusieurs étapes où les états intermédiaires ne doivent pas être exposés
Le Problème : La Pollution du Constructeur
Considérez ce pattern courant :
// ❌ Difficile à lire, facile de mélanger l'ordre des arguments
const request = new ApiRequest('GET', '/users', null, true, 5000, 'json')
Six arguments positionnels. Aucune étiquette. Aucune validation. Si vous inversez deux valeurs, rien ne vous avertit.
Un Exemple Propre du Pattern Builder en JavaScript
Voici une implémentation basée sur les classes utilisant une API fluide en JavaScript—où chaque setter retourne this, permettant le chaînage de méthodes :
class ApiRequestBuilder {
constructor() {
this.method = 'GET' // sensible default
this.url = null
this.body = null
this.timeout = 3000 // default timeout
this.responseType = 'json'
}
setMethod(method) {
this.method = method
return this
}
setUrl(url) {
this.url = url
return this
}
setBody(body) {
this.body = body
return this
}
setTimeout(ms) {
this.timeout = ms
return this
}
build() {
if (!this.url) {
throw new Error('URL is required')
}
// Return a plain, frozen object—not the builder itself
return Object.freeze({
method: this.method,
url: this.url,
body: this.body,
timeout: this.timeout,
responseType: this.responseType,
})
}
}
// Usage
const request = new ApiRequestBuilder()
.setUrl('/api/users')
.setMethod('POST')
.setBody({ name: 'Alice' })
.build()
Chaque appel est auto-documenté. La validation s’exécute dans build() avant l’utilisation de l’objet. Les valeurs par défaut sont appliquées automatiquement. Notez que build() retourne un objet simple figé—pas le builder—ce qui maintient le résultat propre et empêche toute mutation accidentelle.
Discover how at OpenReplay.com.
Builder vs. Alternatives Plus Simples
| Scénario | Meilleure Approche |
|---|---|
| 2-3 champs obligatoires, pas de validation | Littéral d’objet ou fonction factory |
| Champs optionnels, pas de règles | Paramètres nommés via createUser({ name, age }) |
| Champs obligatoires + validation + valeurs par défaut | Pattern Builder |
| Construction complexe en plusieurs étapes | Pattern Builder |
Une fonction factory à paramètres nommés comme createRequest({ url, method = 'GET' }) gère proprement de nombreux cas. Optez pour un builder lorsque la logique de validation ou le séquencement rend cette fonction difficile à comprendre.
Une Note sur TypeScript
TypeScript peut rendre les builders significativement plus sûrs. Vous pouvez imposer que build() ne soit appelable qu’après l’appel des setters obligatoires, en utilisant des types conditionnels ou une interface step-builder. Si votre projet utilise TypeScript, cela vaut la peine d’explorer cette option—mais le pattern JavaScript de base fonctionne bien sans cela.
Conclusion
Utilisez le Pattern Builder lorsque la création d’objet comporte des règles qui doivent être appliquées, et non comme stratégie par défaut de création d’objets. L’API fluide rend le site d’appel lisible, l’étape build() rend la validation explicite, et les valeurs par défaut réduisent le bruit. Pour tout ce qui est plus simple, une fonction factory ou un simple littéral d’objet est le bon outil.
FAQ
Un objet d'options regroupe des paramètres nommés, ce qui résout le problème des arguments positionnels. Un builder ajoute une étape de construction où vous pouvez valider les champs obligatoires, appliquer des contraintes et figer le résultat avant son utilisation. Si vous avez besoin de ces garanties, un builder est le meilleur choix. Si vous avez simplement besoin de clés nommées avec des valeurs par défaut, un objet d'options est plus simple.
Oui, mais soyez prudent. Après avoir appelé build, le builder conserve toujours l'état de la configuration précédente. Vous devez réinitialiser chaque champ ou créer une nouvelle instance de builder pour chaque objet. Créer une nouvelle instance à chaque fois est l'approche la plus sûre et la plus prévisible.
Cela peut être le cas. Si votre objet n'a que quelques champs bien connus et aucune règle de validation, un simple littéral d'objet ou une fonction factory avec des paramètres nommés est plus propre. Le Pattern Builder devient rentable lorsque le nombre de champs optionnels augmente, lorsque les valeurs par défaut interagissent, ou lorsque la création nécessite des contraintes appliquées.
Object.freeze empêche les propriétés de premier niveau de l'objet retourné d'être modifiées après la création. Cela maintient le résultat construit prévisible et en lecture seule, ce qui est particulièrement utile lorsque l'objet est transmis à travers plusieurs couches de code. Cela établit une frontière claire entre le temps de configuration à l'intérieur du builder et le temps d'utilisation à l'extérieur.
Truly understand users experience
See every user interaction, feel every frustration and track all hesitations with OpenReplay — the open-source digital experience platform. It can be self-hosted in minutes, giving you complete control over your customer data. . Check our GitHub repo and join the thousands of developers in our community..