Bonjour,
Envoyé par
professeur shadoko
j'en profite pour relancer une discussion plus générale: les singletons sont-ils souvent une mauvaise idée?
Dans le code que je lis au quotidien (le plus souvent du C++), le singleton est plus souvent mal utilisé que bien utilisé.
Le plus gros problème, ce sont les dépendances implicites. Par exemple, quand on a une routine A qui appelle une routine B qui elle-même appelle une routine C, etc. qui appelle une routine F qui elle-même accède
directement à un singleton MyGlobalDirtyConfig alors, quand on lit le code de la routine A, on ne voit pas que son comportement dépend de l'état de l'instance de la classe MyGlobalDirtyConfig.
Celui qui a introduit à l'arrache la classe MyGlobalDirtyConfig dans le code se rappelle qui dépend de quoi, donc ne sera pas très gêné par cette dépendance implicite quand il modifiera le code. Mais, de nombreuses années après, quand le code aura bien grossi, les malheureux qui récupèreront le projet et qui auront besoin de changer le code de la routine A sans avoir une vision omnisciente du programme risqueront de ne pas savoir que le comportement de A dépend de l'état de l'instance de la classe MyGlobalDirtyConfig. Du coup, des cas particuliers seront oubliés lors de la conception, du codage et des tests. Ensuite, une fois que le code partira en production et que l'instance de la classe MyGlobalDirtyConfig aura un état inhabituel : BOUM : comportement non prévu => anomalie => report de bogue du client => vite, il faut corriger, c'est urgent.
C'est pour ça que, le plus souvent, il faut éviter les variables globales muables et les singletons avec état. À la place, il faut transmettre de paramètre en paramètre ce dont les fonctions ont besoin. On peut voir cela comme une documentation des dépendances en partie vérifiée à la compilation : le comportement d'une fonction dépend de ce qu'on lui passe en paramètre.
Dans le cas particulier du logueur, un logueur singleton est moins grave, car ne pas avoir une vision claire de quel bout de code a besoin de loguer engendre rarement des bogues quand on modifie le code. Cela dit, je pense quand même qu'un logueur singleton est généralement une mauvaise idée.
Personnellement, quand je programme en objet, pour le
logging, je crée une interface
Logger qui n'offre qu'une seule méthode : la méthode qui sert à loguer et qui prend en paramètre un message et un niveau de log. La grande majorité du programme ne connaît que le type de base
Logger. Les fonctions de haut niveau relaient aux fonctions de bas niveau un objet de type
Logger (patron de conception
Stratégie). Seule une petite partie du code connait les classes qui implémentent
Logger.
Comme ça, la majorité du code est réutilisable avec le logueur qu'on veut : il suffit de passer en paramètre l'instance de la classe de log qu'on veut (mais qui doit implémenter l'interface
Logger). On peut même facilement avoir une routine qui logue à un endroit et une autre qui logue à un autre endroit : il suffit de leur passer des logueurs différents en paramètre.
Cela dit, il y a quand même un cas particulier de logueur singleton que je trouve légitime : une classe
NullLogger qui implémente
Logger et qui ne logue rien (patron de conception
Objet nul). Concrètement, cette classe sert donc à désactiver les écritures de logs, ce qui est souvent souhaitable pour les tests unitaires. Comme cette classe n'a pas d'état, il n'y a pas de raison de s'interdire d'en faire un singleton.
Edit 21h46 : reformulation : utilisation du terme "interface" au lieu de "classe de base abstraite" pour mieux coller au vocabulaire de Java.
0 |
0 |