Mon principal argument contre les singletons est en gros qu'ils combinent deux mauvaises propriétés.
Les choses que vous mentionnez peut être un problème, bien sûr, mais ils ne pas avoir à l'être. La synchronisation chose peut être fixe, il ne devient un goulot d'étranglement si le nombre de threads accèdent fréquemment à l'singleton, et ainsi de suite. Ces questions sont ennuyeux, mais pas deal breakers.
Le problème beaucoup plus fondamental avec les singletons, c'est que ce qu'ils essaient de faire est fondamentalement mauvais.
Un singleton, tel que défini par le GoF, a deux propriétés:
- Il est accessible dans le monde entier, et
- Il empêche la classe de jamais être instanciée qu'une seule fois.
Le premier devrait être simple. Globales sont, généralement parlant, mauvais. Si vous ne voulez pas globale, alors vous ne voulez pas un singleton.
La deuxième question est moins évidente, mais fondamentalement, il tente de résoudre un problème inexistant.
Quand était la dernière fois que vous avez accidentellement instancié de la classe, où vous plutôt destinées à la réutilisation d'une instance existante?
Quand était la dernière fois que vous avez accidentellement tapé "std::ostream() << "hello world << std::endl
", lorsque vous signifiait "std::cout << "hello world << std::endl
"?
Il n'a tout simplement pas se produire. Nous n'avons donc pas besoin de prévenir ce problème en premier lieu.
Mais plus important encore, le pressentiment que "seule une instance doit exister" est presque toujours tort.
Ce que nous avons l'habitude de dire est "je ne peut actuellement voir une utilisation pour un exemple".
mais "je ne peux voir que l'utilisation d'une instance" n'est pas la même chose que "l'application s'écrouler si quelqu'un ose la création de deux instances".
Dans ce dernier cas, un singleton peut être justifiée. mais dans le premier cas, c'est vraiment un prématuré est un choix de conception.
Habituellement, nous ne nous envie plus d'une instance.
Vous avez souvent besoin de plus d'un enregistreur. Il y a le journal que vous écrivez propre, des messages structurés, pour le client, de surveiller, et il y a celui de vous faire un dump de débogage de données pour votre propre usage.
Il est également facile d'imaginer que vous pourriez finir vers le haut à l'aide de plus d'une base de données.
Ou de paramètres de programme. Bien sûr, un seul ensemble de paramètres peut être active à la fois. Mais, alors qu'ils sont actifs, l'utilisateur peut entrer dans la "boîte de dialogue" options et configurer un deuxième ensemble de paramètres. Il n'a pas appliqué encore, mais une fois qu'il touche "ok", ils doivent être échangés à l'intérieur et remplacer le jeu actif en cours. Et cela signifie que jusqu'à ce qu'il le hit "ok", deux séries d'options existent réellement.
Et plus généralement, les tests unitaires:
L'une des règles fondamentales de tests unitaires, c'est qu'ils doivent être exécutés dans l'isolement. Chaque essai doit configurer l'environnement à partir de zéro, exécutez le test, et à la déchirure tout en bas. Ce qui signifie que chaque test sera à vouloir créer un nouvel objet singleton, exécutez le test contre elle, et le fermer.
Ce qui n'est évidemment pas possible, en raison d'un singleton est créé une fois et une seule fois. Il ne peut pas être supprimé. De nouvelles instances ne peut pas être créé.
Donc, finalement, le problème avec les singletons n'est pas les subtilités, comme "il est difficile d'obtenir le thread de sécurité correct", mais beaucoup plus fondamentale "ils n'ont pas réellement contribuer à quelque chose de positif à votre code. Ils ajoutent deux traits, chacun d'eux négatif, à votre base de code. Qui voudrait jamais que c'est?"