Question

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, dans lesquels il est logique d'utiliser le singleton.

Était-ce utile?

La solution

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

Une raison qui a tendance à apparaître maintes et maintes fois sur les internets est celle d'un "enregistrement". classe (que vous avez mentionné). 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 solution "acceptable". Singleton, car cela 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 décrit de la manière suivante dans cause fondamentale des singletons , "Les informations présentées ici ne vont que dans un sens: de votre application à l’enregistreur. Même si les enregistreurs sont à l’état global, étant donné qu’aucune information ne circule dans l’application, ils sont acceptables. "

Je suis sûr qu'il y a aussi d'autres raisons valables. Alex Miller, dans " Patterns I Hate ", parle des localisateurs de services et de l'interface utilisateur côté client, qui pourrait également être "acceptable". choix.

En lire plus à Singleton, je vous aime, mais vous me rabaissez.

Autres conseils

Un candidat singleton doit remplir trois conditions:

  • contrôle l'accès simultané à une ressource partagée.
  • l’accès à la ressource sera demandé à plusieurs parties différentes 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.

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

Vous utilisez un singleton lorsque vous devez gérer une ressource partagée. Par exemple, un spouleur d'impression. Votre application ne doit disposer que d’une seule instance du spouleur afin d’éviter des demandes conflictuelles pour la même ressource.

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

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 applicative - single finit toujours par être multiple

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.

Pour utiliser un singleton, vous pouvez notamment couvrir un cas où il doit y avoir un seul "courtier". 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 au cas où vous avez une application avec plusieurs 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 que je voulais lancer dans 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 un "serveur". classe en cours d'exécution dans votre application ... HTH

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 où ce type de modèle peut être vital.

Lorsque vous utilisez Singletons, vous devez vous assurer de ne pas dissimuler des dépendances par inadvertance. 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 les exécutables java), puis transmis à toutes les autres classes instanciées qui en ont besoin. Cela vous aide à maintenir la testabilité.

Vous trouverez un exemple pratique de singleton 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 éléments tels 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, j'avais besoin de 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 a été stocké en tant que données de classe et new () le renverrait toujours. create () a été ajouté pour créer un nouvel objet et activer les tests.

Actuellement, 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. Cela permet même à une classe non-Test :: Builder de jouer en utilisant l'historique de Test :: Builder et les singletons en sortie.

Il semble exister un va-et-vient entre la coordination des données et la flexibilité du comportement que l'on peut atténuer en mettant le singleton unique autour de données partagées avec le moins de comportement possible pour assurer l'intégrité des données.

Lorsque vous chargez un objet 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 lorsque le serveur est en cours d'exécution.

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 fonctionner avec une seule instance d'un objet, il est judicieux d'utiliser des singletons.

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

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

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 un véritable usage des objets - > la classe de modèle contient le modèle de page en cours de création et 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 variables global vous fournit un dépôt de variables 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 ['nom_hôte']

ou ayant toutes les valeurs de langue dans un tableau tel que:

$ gb- & lang; 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 singleton $ gb 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 cela 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 replacer à leur place, par exemple traduites. ou, vous pouvez remplacer dans les structures de page, ou des chaînes de contenu, comme vous le souhaitez.

Vous pouvez utiliser Singleton pour implémenter le modèle d'état (de la manière indiquée dans le livre GoF). En effet, les classes d’états concrètes n’ont pas d’état propre et effectuent leurs actions en termes de classe de contexte.

Vous pouvez également définir Abstract Factory comme un singleton.

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 infrastructures d’injection de dépendance qui utilisent des singletons pour servir de point de connexion au cadre.

Dans ce cas, vous prenez une dépendance de l'infrastructure pour simplifier l'utilisation de la bibliothèque et éviter toute complexité inutile.

Je l'utilise pour un objet encapsulant des paramètres de ligne de commande lorsqu'il s'agit de modules enfichables. Le programme principal ne sait pas quels sont les paramètres de ligne de commande pour les modules chargés (et ne sait même pas toujours quels modules sont chargés). Par exemple, les charges principales A, qui n'ont pas besoin de paramètres eux-mêmes (pourquoi donc prendre un pointeur / une référence supplémentaire / quoi que ce soit, je ne suis pas sûr - ressemble à de la pollution), puis charge les modules X, Y et Z. Deux de ceux-ci, disons X et Z, ont besoin (ou acceptent) de paramètres, ils rappellent donc le singleton en ligne de commande pour lui indiquer les paramètres à accepter, et ils le rappellent au moment de l'exécution pour savoir si l'utilisateur a spécifié d'entre eux.

À bien des égards, un singleton pour gérer les paramètres CGI fonctionnerait de la même manière si vous n’utilisiez qu’un processus par requête (les autres méthodes mod_ * ne le font pas, ce serait donc mauvais ici - donc l’argument qui dit vous ne devriez pas utiliser des singletons dans le monde mod_cgi si vous portez le fichier dans mod_perl ou quel que soit le monde).

Un exemple avec du code, peut-être.

Ici, ConcreteRegistry est un singleton dans un jeu de poker qui permet aux comportements, jusqu’à remonter dans l’arbre des paquets, d’accéder aux quelques interfaces centrales du jeu (c'est-à-dire les façades du modèle, de la vue, du contrôleur, de l'environnement, etc. .):

http://www.edmundkirwan.com/servlet/fractal /cs1/frac-cs40.html

Ed.

1 - Un commentaire sur la première réponse:

Je ne suis pas d'accord avec une classe Logger statique. cela peut être pratique pour une implémentation, mais cela ne peut pas être remplacé pour les tests unitaires. Une classe statique ne peut pas être remplacée par un double test. Si vous ne testez pas les unités, vous ne verrez pas le problème ici.

2 - J'essaie de ne pas créer un singleton à la main. Je viens de créer un objet simple avec des constructeurs qui me permettent d'injecter des collaborateurs dans l'objet. Si j'avais besoin d'un singleton, j'utiliserais un framework d'inyection de dépendances (Spring.NET, Unity pour .NET, Spring pour Java) ou un autre.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top