if(casMetier == cas1) {
// ...
} else if(casMetier == cas2) {
// ...
}...
Cette structure pose de nombreux problèmes. On viole le principe de responsabilité unique, SRP en anglais. D'abord on a une méthode qui fait trop d'actions, le code est plus difficile à lire. On se retrouve avec des méthodes qui font plusieurs centaines de lignes et des classes de plusieurs milliers de lignes. C'est difficile à tester et difficile à maintenir.
Chaque nouvelle fonctionnalité ajoutera du code à cet endroit et la classe grossira encore et toujours...
Alors comment faire ?
J'ai récemment proposé une solution sur projet springboot qui est rapide à mettre en place, une Quick Win.
D'abord j'isole chaque cas métier dans une classe qui implémentera une interface.
public class Cas1 implements ICasMetier {
public void execute() {
//...
}
}
Notre classe principale devient
if(casMetier == cas1) {
cas1.execute();
} else if(casMetier == cas2) {
cas2.execute();
}...
Le code de chaque cas est isolé dans une classe, l'ajout d'un cas se fera dans une nouvelle classe. Ainsi notre classe principale n'est plus responsable de ce code métier. En procédant de cette manière, on peut aussi tester indépendamment chaque cas métier.
C'est une petite victoire, mais on peut encore faire mieux !
En spring on peut charger une liste d'implémentation via l'injection de dépendances
@Autowired
List<ICasMetier> casMetiers;
On a alors une liste qui contient toutes les implémentations de ICasMetiers.
Cool, mais j'en fais quoi ?
Ajoutons une enum qui va définir les types de cas métiers.
enum TypeCasMetierEnum {
CAS_1,
CAS_2;
}
J'associe les valeurs aux implémentations
class Cas1 implements ICasMetier {
public TypeCasMetierEnum getType(){
return CAS_1;
}
}
Et maintenant retournons dans la classe principale.
Map<TypeCasMetierEnum, ICasMetier> casMetierByType = casMetiers.stream()
.collect(Collectors.toMap(ICasMetier::getType, Function.identity()));
On a une Map qui nous permet d'accéder à la bonne implémentation de ICasMetier grâce au type. C'est bientôt fini, on peut transformer le if simplement en :
casMetierByType.get(casMetier).execute();
Notre suite de if est remplacé par une simple ligne de code. Dorénavant, chaque nouveau cas métier nécessitera qu'une implémentation de la classe ICasMetier. Le code de notre classe principale ne bouge plus. Pour être garantir le bon fonctionnement de ce mécanisme, on peut ajouter un TU qui vérifie que chaque valeur de l'enum est bien associée à une implémentation de ICasMetier.
C'est tout pour aujourd'hui, à bientôt.