J'ai vu des gens dans SO commenter que Singleton Pattern est un anti-pattern. Je veux savoir pourquoi?
Test
L'une des raisons est que les singletons ne sont pas faciles à gérer avec les tests unitaires. Vous ne pouvez pas contrôler l'instanciation et, de par leur nature même, peuvent conserver l'état à travers les appels.
Pour cette raison, le principe de injection de dépendances est populaire. Chaque classe est injectée (configurée) avec les classes dont elle a besoin pour fonctionner (plutôt que de dériver via des accesseurs singleton) et ainsi les tests peuvent contrôler les instances de classe dépendantes à utiliser (et fournir des simulations si nécessaire).
Les frameworks tels que Spring contrôlent le cycle de vie de leurs objets et créent souvent des singletons, mais ces objets sont injectés dans leurs objets dépendants par le framework. Ainsi, la base de code elle-même ne traite pas les objets comme des singletons.
par exemple. plutôt que ça (par exemple)
public class Portfolio {
private Calculator calc = Calculator.getCalculator();
}
vous injecteriez la calculatrice:
public class Portfolio {
public Portfolio(Calculator c) {
this.calc = c;
}
}
Ainsi, l'objet Portfolio
ne sait pas/ne se soucie pas du nombre d'instances de Calculator
qui existent. Les tests peuvent injecter une valeur factice Calculator
qui facilite les tests.
Concurrence
En vous limitant à une seule instance d'un objet, les options de threading sont limitées. L'accès à l'objet singleton peut devoir être protégé (par exemple via la synchronisation). Si vous pouvez gérer plusieurs instances de ces objets, vous pouvez adapter le nombre d'instances aux threads que vous exécutez et augmenter les capacités simultanées de votre base de code.
Mon opinion personnelle est qu'elle enfreint le principe de responsabilité unique. Les objets Singleton sont responsables à la fois de leur objectif et du contrôle du nombre d'instances qu'ils produisent, ce qui, à mon avis, est faux.
C'est pourquoi de nombreuses personnes délèguent le contrôle à un objet de fabrique.
[Mutable] Singleton est un anti-pattern d'un anti-pattern.
L'anti-pattern sous-jacent significatif est l'état global (ou état ambiant). Avec l'état global, vous avez un grand blog de dépendance dans votre programme. Cela affecte les tests, mais ce n'est qu'une partie des retombées d'une mauvaise programmation.
En plus de cela, Singleton ajoute un niveau de complexité complètement inutile par rapport à la simple déclaration de champs static
mutables.
Les singletons en tant que tels ne sont pas nécessairement un anti-modèle, mais ils n'ont que peu d'avantages et deviennent un anti-modèle lorsqu'ils sont mal utilisés (ce qui arrive souvent).
Souvent, les singletons ne sont pas du tout des singletons, mais des "variables globales déguisées". En outre, ils sont souvent utilisés lorsque la propriété "une seule instance" n'est en fait pas un avantage. (ce qui est à nouveau contrebalancé par le fait que la mise en œuvre est souvent erronée en même temps).
En plus de cela, ils peuvent être difficiles à implémenter avec le multithreading à l'esprit (souvent mal ou inefficace), et ils perdent la plupart de leurs avantages si vous souhaitez contrôler leur instanciation.
Si vous voulez avoir le contrôle sur l'instanciation, vous devez le faire à la main à un moment donné au début du programme, mais vous pouvez tout aussi bien créer une instance d'un objet normal et la transmettre.
Si l'ordre de destruction est un problème, vous devez également l'implémenter manuellement. Un seul objet automatique dans la fonction principale est tellement plus propre et plus facile.
Il existe de nombreuses exigences que vous pourriez avoir sur le singleton:
En règle générale, vous aurez également de nombreux singletons dans votre application, et le modèle Singleton n'autorise pas le code réutilisable. Donc, si vous voulez implémenter toutes ces préoccupations pour tous vos singletons, vous verrez immédiatement sa qualité anti-pattern.
Étrange. Il semble que l'implémentation incorrecte d'un Singleton soit un "anti-pattern", pas le Singleton lui-même.
Je pense que nous avons oublié que chaque programme doit commencer quelque part. Il doit y avoir une implémentation concrète de chaque abstraction, et finalement chaque dépendance sera finalement résolue, ou votre application ne serait pas très utile.
La plupart des frameworks DI permettent d'instancier une classe en tant que Singleton, il le gère juste pour vous. Si vous choisissez de faire vous-même la DI, l'injection d'un singleton n'est pas un problème. Un Singleton IS testable également, et si vous utilisez DI pour l'injecter, ne rend pas une classe instable.
IMO, comme tous les autres modèles (y compris DI et IoC), c'est un outil. Parfois ça va, parfois non.