☕ 5 min de lecture
Supposons que les méthodes suivantes existent :
function sayHello() {
console.log('Hello, how are you?')
}
function giveSomeNews() {
console.log('Roses are red. Did you know that?')
}
function sayBye() {
console.log('Ok bye!')
}
switch
if / else
permet d’introduire de la logique dans notre code en créant des branches : en fonction d’une condition, nous exécuterons telle ou telle opération. Mais parfois, il y a plus de 2 branches possibles.
Le réflexe initial consiste donc à ajouter des branches avec else if
:
if (name === 'patrick') {
sayHello()
} else if (name === 'jane') {
giveSomeNews()
} else {
sayBye() // don't talk to strangers!
}
Comme c’est un petit peu verbeux, peu lisible et encore moins élégant, on utilise alors le switch
:
switch (name) {
case 'patrick':
sayHello()
break
case 'jane':
giveSomeNews()
break
default:
sayBye() // don't talk to strangers!
break
}
switch
est une alternative classique à un enchaînement de else if
.
À moins qu’il s’agisse d’opérations très petites (quelques lignes, claires et explicites), je préfère les encapsuler dans des fonctions explicitement nommées pour décomposer la logique de l’implémentation. Le switch
, c’est la logique. J’utilise la même technique pour les if / else
.
La syntaxe est plus claire, mais on introduit certaines subtilités.
Notamment, il faut prendre garde au concept du break
introduit ici : il permet de sortir du switch
et éviter de passer au case
suivant.
Lorsque l’on arrive sur un switch
, on s’attend rarement (jamais ?) à passer à travers 2 cas différents.
À l’instar du else if
, on s’attend à exécuter un cas et un seul. Pour cette raison, on veille à ne pas oublier le break
!
Par exemple, ce code est-il intentionnel ? Est-ce un oubli ? En tout cas, c’est une source de confusion et de bugs !
switch (name) {
case 'patrick':
sayHello()
break
case 'jane':
giveSomeNews()
default:
sayBye() // don't talk to strangers!
break
}
Il existe un cas de figure où, à la limite, l’intention reste claire et qui est acceptable (et utilisée).
Il s’agit de regrouper différents inputs dans un même case
:
switch (name) {
case 'patrick':
sayHello()
break
case 'jane':
case 'john':
giveSomeNews()
break
default:
sayBye() // don't talk to strangers!
break
}
Bref, ne pas mettre un break
à chaque case
est très souvent propice aux erreurs car le code écrit comporte “une subtilité”, il a donc des chances d’être mal lu / interprété.
Le jeu n’en vaut pas la chandelle, aussi je vous conseille plutôt de ne pas le faire. Après, c’est vous qui voyez mais y’en a qu’on essayé…
Reprenons à présent notre exemple avec un esprit moins procédural, plus orienté-objet :
var greetings = {
patrick: sayHello,
john: giveSomeNews,
jane: giveSomeNews,
}
typeof greetings[name] === 'function' ? greetings[name]() : sayBye()
On peut appeler cela le method lookup qui traduit finalement l’idée du Command Pattern.
On utilise ici la syntaxe objet naturelle de JavaScript et la puissance de ses fonctions. Pas de break
dont on doit se préoccuper. On dispose également de tous les avantages de l’objet, notamment le fait de pouvoir le surcharger facilement et ainsi dépendre d’un contexte particulier.
En pratique, le method lookup est pertinent par rapport au switch si vous vous trouvez dans l’un des cas suivants :
case 1:
, case 2:
, etc.break
? Fall through = danger, le method lookup est bien plus clair.switch
“avancé”Avec switch
il est possible de tester directement une condition dans le case
.
Ainsi, en considérant que ceci existe :
function isPatrick(name) {
return name === 'patrick'
}
function isJane(name) {
return /^jane-/.test(name)
}
Le code suivant fonctionne parfaitement :
switch (true) {
case isPatrick(name):
sayHello()
break
case isJane(name):
giveSomeNews()
break
default:
sayBye() // don't talk to strangers!
break
}
Pour plus de lisibilité, j’ai effectivement exporté les case
dans des fonctions qui expriment clairement l’intention afin de produire un code clair avec cette syntaxe.
Vous conviendrez que la logique est à présent un poil plus complexe. Dans ce cas, il est donc judicieux de travailler à rendre le code plus clair.
Ceci fonctionne, peut se révéler utile et n’a pas d’équivalent avec la method lookup (que je sache).
Cela étant, prenez garde aux abus de logique. Ce n’est pas parce-qu’on peut le faire, qu’on doit le faire. Veillez à garder un esprit critique sur ce que vous faîtes : est-ce vraiment nécessaire ou existe-t-il un moyen plus simple ? Peut-on trouver design plus clair pour exprimer cette logique ?
Parfois on s’emporte dans des trucs “sexy”, mais un bon KISS ne fait jamais de mal !
Le method lookup / command pattern est l’équivalent du switch
dans un esprit objet. Il tend à encourager l’écriture d’un code flexible, bien organisé, orienté-objet (et ça, c’est bien !).
Si switch … case
n’est pas mauvais en soi, il peut s’avérer propice aux erreurs et encourage en soi le spaghetti code. Par sa nature procédurale, il peut conduire à une logique de branche complexe qui résulte souvent dans un mauvais design et donc un code peu difficile à maintenir.
En fait, il n’y a pas vraiment de raison d’utiliser switch
plutôt que son alternative quand on veut profiter de ce que JavaScript offre. Le principal, c’est de produire un code clair pour votre future-vous et les autres !