web-dev-qa-db-fra.com

Modèles de design: Quand devrais-je utiliser le singleton?

La variable globale glorifiée - devient une classe globale glorifiée. Certains disent briser la conception orientée objet.

Donnez-moi des scénarios, autres que le bon vieil enregistreur, où il est logique d'utiliser le singleton.

410
Setori

Dans ma quête de la vérité, j'ai découvert qu'il y avait en réalité très peu de raisons "acceptables" d'utiliser un Singleton.

Une raison qui a tendance à apparaître maintes et maintes fois sur les internets est celle d'une classe de "journalisation" (que vous avez mentionnée). Dans ce cas, un Singleton peut être utilisé à la place d'une instance unique d'une classe car une classe de journalisation doit généralement être utilisée encore et encore ad nauseam par chaque classe d'un projet. Si chaque classe utilise cette classe de journalisation, l'injection de dépendance devient lourde.

La journalisation est un exemple spécifique de Singleton "acceptable" car il n'affecte pas l'exécution de votre code. Désactiver la journalisation, l'exécution du code reste la même. Activez-le, pareil. Misko le résume de la manière suivante: cause fondamentale des singletons , "Les informations présentées ne sont transmises que de la même manière: de votre application à l’enregistreur. Même si les enregistreurs sont à l’état global, aucune information application, les enregistreurs sont acceptables. "

Je suis sûr qu'il y a aussi d'autres raisons valables. Alex Miller, dans " Patterns I Hate ", indique que les localisateurs de services et l'interface utilisateur côté client sont également des choix "acceptables".

En lire plus à Singleton, je t'aime, mais tu me rabats.

339

Un candidat Singleton doit satisfaire à trois exigences:

  • contrôle l'accès simultané à une ressource partagée.
  • l'accès à la ressource sera demandé à partir de multiples parties du système.
  • il ne peut y avoir qu'un seul objet.

Si votre Singleton proposé ne répond qu'à une ou deux de ces exigences, une refonte est presque toujours la bonne option.

Par exemple, il est peu probable qu'un spouleur d'impression soit appelé de plusieurs endroits (menu Imprimer). Vous pouvez donc utiliser des mutex pour résoudre le problème de l'accès simultané.

Un simple enregistreur est l'exemple le plus évident d'un Singleton éventuellement valide, mais cela peut changer avec des schémas d'enregistrement plus complexes.

119
metao

Lire des fichiers de configuration qui ne doivent être lus qu'au démarrage et les encapsuler dans un singleton.

42
Paul Croarkin

Vous utilisez un singleton lorsque vous devez gérer une ressource partagée. Par exemple, un spouleur d'impression. Votre application ne doit avoir qu'une seule instance du spouleur afin d'éviter tout conflit de demande pour la même ressource.

Ou une connexion à une base de données ou un gestionnaire de fichiers, etc.

35
Vincent Ramdhanie

Les singletons en lecture seule stockant un état global (langue de l'utilisateur, chemin d'accès au fichier d'aide, chemin d'accès à l'application) sont raisonnables. Veillez à utiliser des singletons pour contrôler la logique de gestion - single finit toujours par être multiple

23
Martin Beckett

Gestion d'une connexion (ou d'un pool de connexions) à une base de données.

Je l’utiliserais aussi pour récupérer et stocker des informations sur des fichiers de configuration externes.

16

Pour utiliser un singleton, vous pouvez notamment couvrir une instance dans laquelle un seul "courtier" doit contrôler l'accès à une ressource. Les singletons sont utiles dans les enregistreurs, car ils facilitent l'accès à un fichier, qui ne peut être écrit que de manière exclusive. Pour quelque chose comme la journalisation, ils fournissent un moyen de résumer les écritures dans quelque chose comme un fichier journal - vous pouvez encapsuler un mécanisme de mise en cache dans votre singleton, etc.

Pensez également à une situation dans laquelle vous avez une application avec beaucoup de fenêtres/threads/etc., mais qui nécessite un point de communication unique. Une fois, j'en ai utilisé un pour contrôler les travaux pour lesquels je souhaitais lancer mon application. Le singleton était responsable de la sérialisation des travaux et de l'affichage de leur statut à toute autre partie du programme intéressée. Dans ce type de scénario, vous pouvez considérer un singleton comme une sorte de classe "serveur" s'exécutant dans votre application ... HTH

10
Dave Markle

Un singleton doit être utilisé lors de la gestion de l'accès à une ressource partagée par l'application entière. Il serait également destructeur de posséder plusieurs instances de la même classe. S'assurer que l'accès aux ressources partagées thread-safe est un très bon exemple de cas dans lesquels ce type de modèle peut être vital.

Lorsque vous utilisez Singletons, vous devez vous assurer que vous ne cachez pas accidentellement des dépendances. Idéalement, les singletons (comme la plupart des variables statiques dans une application) doivent être configurés lors de l'exécution du code d'initialisation de l'application (static void Main () pour les exécutables C #, static void main () pour Java exécutables ), puis transmis à toutes les autres classes instanciées qui en ont besoin. Cela vous aide à maintenir la testabilité.

10
Adam Ness

Un exemple pratique de singleton peut être trouvé dans Test :: Builder , la classe qui supporte à peu près tous les modules de test Perl modernes. Le singleton Test :: Builder stocke et assure le courtage de l’état et de l’historique du processus de test (résultats de test historiques, compte du nombre de tests exécutés), ainsi que des informations telles que l’orientation de la sortie du test. Tous ces éléments sont nécessaires pour coordonner plusieurs modules de test, écrits par différents auteurs, afin de travailler ensemble dans un seul script de test.

L'histoire du singleton de Test :: Builder est éducative. L'appel de new() vous donne toujours le même objet. Tout d'abord, toutes les données ont été stockées sous forme de variables de classe sans rien dans l'objet lui-même. Cela a fonctionné jusqu'à ce que je veuille tester Test :: Builder avec lui-même. Ensuite, il me fallait deux objets Test :: Builder, un en tant que mannequin pour capturer et tester son comportement et sa sortie, et un pour être le véritable objet de test. À ce stade, Test :: Builder a été refactoré en un objet réel. L'objet singleton était stocké en tant que données de classe et new() le renverrait toujours. create() a été ajouté pour créer un nouvel objet et permettre les tests.

À l'heure actuelle, les utilisateurs souhaitent modifier certains comportements de Test :: Builder dans leur propre module, tout en en laissant d'autres, tandis que l'historique des tests reste commun à tous les modules de test. Ce qui se passe maintenant, c'est que l'objet monolithique Test :: Builder est divisé en éléments plus petits (historique, sortie, format ...) avec une instance de Test :: Builder qui les rassemble. Maintenant, Test :: Builder ne doit plus être un singleton. Ses composants, comme l'histoire, peuvent être. Cela repousse la nécessité inflexible d'un singleton à un niveau inférieur. Cela donne plus de flexibilité à l'utilisateur pour mélanger et assortir des morceaux. Les objets singleton plus petits peuvent désormais simplement stocker des données, leurs objets les contenant décidant de leur utilisation. Il permet même à une classe non-Test :: Builder de jouer en utilisant l'historique :: Test :: Builder et les singletons en sortie.

Il semble y avoir un va-et-vient entre la coordination des données et la flexibilité du comportement qui peut être atténué en plaçant le singleton autour de données partagées avec le moins de comportement possible pour assurer leur intégrité.

6
Schwern

Je pense que l'utilisation de singleton peut être considérée comme la même chose que la relation plusieurs-à-un dans les bases de données. Si de nombreuses parties de votre code doivent travailler avec une seule instance d'un objet, il est judicieux d'utiliser des singletons.

5
daalbert

Lorsque vous chargez un objet Propriétés de configuration, à partir de la base de données ou d'un fichier, il est utile de l'avoir en tant que singleton. il n'y a aucune raison de continuer à relire des données statiques qui ne changeront pas pendant le fonctionnement du serveur.

5
Dean J

Vous pouvez utiliser Singleton lors de la mise en œuvre du modèle d'état (de la manière indiquée dans le livre GoF). En effet, les classes d'état concrètes n'ont pas d'état et effectuent leurs actions en termes de classe de contexte.

Vous pouvez également faire de Abstract Factory un singleton.

3
Emile Cormier

Comme tout le monde l’a dit, une ressource partagée, en particulier quelque chose qui ne peut pas gérer l’accès simultané.

Un exemple spécifique que j’ai vu est celui de Lucene Search Index Writer.

3
Mike

Ressources partagées En particulier en PHP, une classe de base de données, une classe de modèle et une classe de dépôt de variable globale. Tous doivent être partagés par tous les modules/classes utilisés dans le code.

C'est une véritable utilisation d'objet -> la classe de modèle contient le modèle de page en cours de construction. Il est mis en forme, ajouté, modifié par les modules ajoutés à la sortie de la page. Il doit être conservé comme une instance unique pour que cela puisse arriver, de même que pour les bases de données. Avec un singleton de base de données partagée, les classes de tous les modules peuvent accéder aux requêtes et les obtenir sans avoir à les réexécuter.

Un singleton de dépôt de variable global vous fournit un dépôt de variable global, fiable et facilement utilisable. Cela arrange beaucoup votre code. Imaginez avoir toutes les valeurs de configuration dans un tableau dans un singleton tel que:

$gb->config['hostname']

ou ayant toutes les valeurs de langue dans un tableau comme:

$gb->lang['ENTER_USER']

À la fin de l'exécution du code de la page, vous obtenez, par exemple, un message maintenant mature:

$template

Singleton, un $gb singleton qui contient le tableau lang à remplacer, ainsi que toutes les sorties chargées et prêtes. Vous venez de les remplacer dans les clés qui sont maintenant présentes dans la valeur de page de l'objet modèle mature, puis vous les transmettez à l'utilisateur.

Le grand avantage de ceci est que vous pouvez effectuer TOUT traitement de post-traitement que vous préférez. Vous pouvez diriger toutes les valeurs de langue vers google translate ou un autre service de traduction et les récupérer, puis les remplacer à leur place, par exemple traduites. ou, vous pouvez remplacer dans les structures de page, ou des chaînes de contenu, comme vous le souhaitez.

3
Ozgur Zeren

Il peut être très pragmatique de configurer des problèmes d’infrastructure spécifiques en tant que singletons ou variables globales. Mon exemple préféré est celui des frameworks d’injection de dépendance qui utilisent des singletons comme point de connexion au framework.

Dans ce cas, vous dépendez de l’infrastructure pour simplifier l’utilisation de la bibliothèque et éviter toute complexité inutile.

1
smaclell