Pourquoi il faut déclarer ses classes "final"
Frédéric Bouchery
Posted on April 1, 2023
(English version: Why your class must be final)
Lorsque je code avec d'autres développeuses ou développeurs, en pair programming ou en groupe, on me demande souvent : "Pourquoi déclares-tu toutes tes classes "final
?".
Ma réponse a toujours été : C'est une bonne pratique pour moi, héritée de mon expérience avec Delphi, où toutes les classes sont "final
" par défaut.
Cependant, lorsque l'on me demande pourquoi c'est une bonne pratique, j'ai réalisé que je devais être plus précis.
L'utilisation du mot-clé "final
" peut aider à éviter le inheritance hell, en référence aux interminables et complexes hiérarchies de classes, dans laquelle il est difficiles de se retrouve, et de comprendre.
L'héritage peut rendre les tests et le débogage plus difficiles, en particulier lorsqu'il s'agit de chaînes d'héritage complexes avec des dépendances dans tous les sens. En d'autres termes, l'héritage peut entraîner un code fragile et une complexité accrue.
Un autre problème avec l'héritage est qu'il crée un couplage fort entre la classe de base et la classe dérivée, rendant plus difficile le changement de la classe de base sans affecter les classes dérivées et cela peut rendre le code plus difficile à maintenir dans le temps.
Récemment, j'ai apporté des modifications à une bibliothèque PHP qui utilise la terminologie "maître/esclave" et je voulais effectuer les modifications suivantes :
- Renommer les méthodes "
master()
" en "primary()
" et "slave()
" en "replica()
" - Ajouter des méthodes dépréciées "
master()
" et "slave()
" qui appellent les méthodes "primary()
" et "replica()
" - Ajouter un commentaire à la méthode dépréciée "
slave()
" pour expliquer les raisons du changement (connotations négatives).
Le problème, c'est que la classe définissait également une propriété appelée "$slaveConnection
" qui était déclarée comme protected
.
J'aurais aimé changer également son nom, mais je ne pouvais pas le faire car elle était peut-être utilisée par une classe enfant.
J'ai envisagé de déclarer la propriété comme private
et utiliser des getters et des setters magiques pour permettre aux classes enfants d'écrire et de lire le nom de la propriété déprécié, mais j'ai estimé que cela ajoutait une complexité inutile pour résoudre quelque chose dont je suis sûr que ce n'est pas utilisé. Bien que cette bibliothèque soit open source, elle n'est pas très populaire, et la probabilité que cette classe soit redéfinie, dans un obscure bout de code, fait par une personne dans un coin sombre d'internet, est proche de zéro.
Pour éviter d'introduire des changements qui casserait la compatibilité du code, j'ai conservé ce nom offensant et ajouté un commentaire expliquant qu'il était conservé pour des raisons de compatibilité, mais je n'approuvais pas le nom.
Comme vous le comprenez, parce que la classe n'est pas final
, et même si je suis sûr qu'elle n'est pas redéfinie, je ne peux pas faire mon changement. Si le développeur ou la développeuse qui avait conçu cette classe, avait le réflexe de déclarer final
toutes ses classes, je n'aurais jamais rencontré ce problème. D'ailleurs, si on veut redéfinir la classe plus tard, il est beaucoup plus simple de supprimer le mot clé final
sans générer de casse de compatibilité.
En conclusion, déclarer toutes vos classes final par défaut peut faire gagner du temps aux générations futures de développeurs qui maintiendront votre code.
(source des photos: pexels.com)
Posted on April 1, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.