Je travaille actuellement sur une webapp où nous devons souvent conditionner une logique de serveur basée sur la page qui va être retournée à l'utilisateur.
Chaque page reçoit un code de page à 4 lettres, et ces codes de page sont actuellement répertoriés dans une classe en tant que chaînes statiques:
public class PageCodes {
public static final String FOFP = "FOFP";
public static final String FOMS = "FOMS";
public static final String BKGD = "BKGD";
public static final String ITCO = "ITCO";
public static final String PURF = "PURF";
// etc..
}
Et souvent dans le code, nous voyons un code comme celui-ci ( 1ère forme ):
if (PageCode.PURF.equals(destinationPageCode) || PageCodes.ITCO.equals(destinationPageCode)) {
// some code with no obvious intent
}
if (PageCode.FOFP.equals(destinationPageCode) || PageCodes.FOMS.equals(destinationPageCode)) {
// some other code with no obvious intent either
}
Ce qui est un peu horrible à lire car il ne montre pas quelle propriété commune de ces pages a conduit l'auteur du code à les rassembler ici. Nous devons lire le code dans la if
branche pour comprendre.
Solution actuelle
Ces if
s ont été en partie simplifiés en utilisant des listes de pages qui sont déclarées par différentes personnes dans différentes classes. Cela fait ressembler le code ( 2e forme ):
private static final List<String> pagesWithShoppingCart = Collections.unmodifiableList(Arrays.asList(PageCodes.ITCO, PageCodes.PURF));
private static final List<String> flightAvailabilityPages = Collections.unmodifiableList(Arrays.asList(PageCodes.FOMS, PageCodes.FOFP));
// later in the same class
if (pagesWithShoppingCart.contains(destinationPageCode)) {
// some code with no obvious intent
}
if (flightAvailabilityPages.contains(destinationPageCode)) {
// some other code with no obvious intent either
}
... qui exprime bien mieux l'intention. Mais...
Problème actuel
Le problème ici est que si nous ajoutons une page, nous aurions en théorie besoin de parcourir toute la base de code pour savoir si nous devons ajouter notre page à une if()
ou à une liste comme celle-ci.
Même si nous avons déplacé toutes ces listes dans la PageCodes
classe en tant que constantes statiques, les développeurs ont toujours besoin de discipline pour vérifier si leur nouvelle page tient dans l'une de ces listes et l'ajouter en conséquence.
Nouvelle solution
Ma solution a été de créer une énumération (car il existe une liste finie bien connue de codes de page) où chaque page contient des propriétés que nous devons définir:
public enum Page {
FOFP(true, false),
FOMS(true, false),
BKGD(false, false),
PURF(false, true),
ITCO(false, true),
// and so on
private final boolean isAvailabilityPage;
private final boolean hasShoppingCart;
PageCode(boolean isAvailabilityPage, boolean hasShoppingCart) {
// field initialization
}
// getters
}
Ensuite, le code conditionnel ressemble maintenant à ceci ( 3e forme ):
if (destinationPage.hasShoppingCart()) {
// add some shopping-cart-related data to the response
}
if (destinationPage.isAvailabilityPage()) {
// add some info related to flight availability
}
Ce qui est très lisible. De plus, si quelqu'un a besoin d'ajouter une page, il est obligé de penser à chaque booléen et si c'est vrai ou faux pour sa nouvelle page.
Nouveau problème
Un problème que je vois, c'est qu'il y aura peut-être 10 booléens comme celui-ci, ce qui rend le constructeur très gros et il pourrait être difficile d'obtenir la bonne déclaration lorsque vous ajoutez une page. Quelqu'un at-il une meilleure solution?
false
, puis en modifier un ou deux (probablement le mauvais, car il est si difficile de garder une trace). Il n'y a pas de protection parfaite contre les stupides, et il arrive un moment où vous devez faire confiance à vos développeurs pour faire la bonne chose.