Quand devriez-vous utiliser le modèle singleton au lieu d’une classe statique?

Nommez les considérations de conception en décidant entre l’utilisation d’un singleton et d’une classe statique. En faisant cela, vous êtes en quelque sorte obligé de contraster les deux, donc tous les contrastes que vous pouvez trouver sont également utiles pour montrer votre processus de pensée! En outre, chaque intervieweur aime voir des exemples illustratifs. 🙂

  • Les singletons peuvent implémenter des interfaces et hériter d’autres classes.
  • Les singletons peuvent être chargés paresseux. Seulement quand c’est réellement nécessaire. C’est très pratique si l’initialisation comprend un chargement de ressources coûteux ou des connexions à une firebase database.
  • Les singletons offrent un object réel.
  • Les singletons peuvent être étendus dans une usine. La gestion des objects en coulisse est abstraite, ce qui la rend plus facile à entretenir et aboutit à un meilleur code.

Qu’en est-il de “éviter les deux”? Singletons et classes statiques:

  • Peut introduire un état mondial
  • Être étroitement couplé à plusieurs autres classes
  • Masquer les dépendances
  • Peut rendre difficile les classes de tests unitaires

Au lieu de cela, examinez les bibliothèques d’ dependency injections et d’ inversion des conteneurs de contrôle . Plusieurs bibliothèques d’IoC gèreront la gestion de la durée de vie pour vous.

(Comme toujours, il existe des exceptions, telles que les classes mathématiques statiques et les méthodes d’extension C #.)

Je dirais que la seule différence est la syntaxe: MySingleton.Current.Whatever () vs MySingleton.Whatever (). L’Etat, comme l’a mentionné David, est finalement «statique» dans les deux cas.


EDIT: La brigade d’enterrement est venue de digg … de toute façon, j’ai pensé à un cas qui nécessiterait un singleton. Les classes statiques ne peuvent pas hériter d’une classe de base ni implémenter une interface (du moins dans .Net, elles ne le peuvent pas). Donc, si vous avez besoin de cette fonctionnalité, vous devez utiliser un singleton.

Une de mes discussions préférées sur ce sujet est ici (site original, maintenant lié à Internet Archive Wayback Machine .)

Pour résumer les avantages de flexibilité d’un Singleton:

  • un Singleton peut être facilement converti en usine
  • un singleton peut être facilement modifié pour retourner différentes sous-classes
  • cela peut entraîner une application plus maintenable

Une classe statique avec une charge de variables statiques est un peu un hack.

 /** * Grotty static semaphore **/ public static class Ugly { private static int count; public synchronized static void increment(){ count++; } public synchronized static void decrement(){ count--; if( count<0 ) { count=0; } } public synchronized static boolean isClear(){ return count==0; } } 

Un singleton avec une instance réelle est préférable.

 /** * Grotty static semaphore **/ public static class LessUgly { private static LessUgly instance; private int count; private LessUgly(){ } public static synchronized getInstance(){ if( instance==null){ instance = new LessUgly(); } return instance; } public synchronized void increment(){ count++; } public synchronized void decrement(){ count--; if( count<0 ) { count=0; } } public synchronized boolean isClear(){ return count==0; } } 

L'état est UNIQUEMENT dans l'instance.

Ainsi, le singleton peut être modifié ultérieurement pour effectuer des regroupements, des instances locales de threads, etc. Et aucun des codes déjà écrits n'a besoin d'être modifié pour en tirer profit.

 public static class LessUgly { private static Hashtable session; private static FIFO freePool = new FIFO(); private static final POOL_SIZE=5; private int count; private LessUgly(){ } public static synchronized getInstance(){ if( session==null){ session = new Hashtable(POOL_SIZE); for( int i=0; i < POOL_SIZE; i++){ LessUgly instance = new LessUgly(); freePool.add( instance) } } LessUgly instance = session.get( Session.getSessionID()); if( instance == null){ instance = freePool.read(); } if( instance==null){ // TODO search sessions for expired ones. Return spares to the freePool. //FIXME took too long to write example in blog editor. } return instance; } 

Il est possible de faire quelque chose de similaire avec une classe statique, mais il y aura une surcharge par appel dans la dissortingbution indirecte.

Vous pouvez obtenir l'instance et la transmettre à une fonction en tant qu'argument. Cela permet au code d'être dirigé vers le "droit" singleton. Nous soaps que vous n'en aurez besoin que d'une fois ...

Le grand avantage est que les singletons avec état peuvent être rendus sûrs, alors qu'une classe statique ne le peut pas, à moins que vous ne le modifiiez comme un singleton secret.

Pensez à un singleton comme un service. C’est un object qui fournit un ensemble spécifique de fonctionnalités. Par exemple

 ObjectFactory.getInstance().makeObject(); 

La fabrique d’objects est un object qui exécute un service spécifique.

En revanche, une classe pleine de méthodes statiques est un ensemble d’actions que vous pouvez effectuer, organisées dans un groupe associé (la classe). Par exemple

 SsortingngUtils.reverseSsortingng("Hello"); SsortingngUtils.concat("Hello", "World"); 

L’exemple SsortingngUtils ici est une collection de fonctionnalités pouvant être appliquées n’importe où. L’object singleton factory est un type d’object spécifique avec une responsabilité claire pouvant être créée et transmise si nécessaire.

Les classes statiques sont instanciées à l’exécution. Cela pourrait prendre beaucoup de temps. Les singletons ne peuvent être instanciés que lorsque cela est nécessaire.

Les singletons ne doivent pas être utilisés de la même manière que les classes statiques. En essence,

 MyStaticClass.GetInstance().DoSomething(); 

est essentiellement le même que

 MyStaticClass.DoSomething(); 

Ce que vous devriez réellement faire, c’est de traiter le singleton comme un simple object . Si un service nécessite une instance du type singleton, transmettez cette instance au constructeur:

 var svc = new MyComplexServce(MyStaticClass.GetInstance()); 

Le service ne doit pas savoir que l’object est un singleton et doit traiter l’object comme un simple object.

L’object peut certainement être implémenté, en tant que détail d’implémentation et en tant qu’aspect de la configuration globale, en tant que singleton si cela facilite les choses. Mais les choses qui utilisent l’object ne devraient pas avoir à savoir si l’object est un singleton ou non.

Si, par “classe statique”, vous voulez dire une classe qui ne contient que des variables statiques, elle peut en réalité maintenir l’état. Ma compréhension est que la seule différence serait la façon dont vous accédez à cette chose. Par exemple:

 MySingleton().getInstance().doSomething(); 

contre

 MySingleton.doSomething(); 

Les composants internes de MySingleton seront évidemment différents entre eux mais, mis à part les problèmes de sécurité des threads, ils auront tous deux la même chose en ce qui concerne le code client.

Le modèle Singleton est généralement utilisé pour traiter des données indépendantes ou statiques d’instance où plusieurs threads peuvent accéder aux données en même temps. Un exemple peut être des codes d’état.

Les singletons ne devraient jamais être utilisés (sauf si vous considérez une classe sans état mutable un singleton). Les “classes statiques” ne devraient avoir aucun état mutable, à part peut-être des caches sans risque de thread et similaires.

Pratiquement n’importe quel exemple de singleton montre comment ne pas le faire.

Si vous pouvez vous débarrasser d’un singleton pour le nettoyer après, vous pouvez le prendre en compte lorsqu’il s’agit d’une ressource limitée (c’est-à-dire une seule d’entre elles) dont vous n’avez pas besoin tout le temps. coût de la ressource quand il est alloué.

Le code de nettoyage semble plus naturel lorsque vous avez un singleton, par opposition à une classe statique contenant des champs d’état statique.

Le code, cependant, aura la même apparence, donc si vous avez des raisons plus spécifiques de demander, vous devriez peut-être élaborer.

Les deux peuvent être assez similaires, mais rappelez-vous que le vrai Singleton doit lui-même être instancié (accordé, une fois) et ensuite servi. Une classe de firebase database PHP qui renvoie une instance de mysqli n’est pas vraiment un singleton (comme certains l’appellent), car elle renvoie une instance d’une autre classe, et non une instance de la classe qui possède l’instance en tant que membre statique.

Donc, si vous écrivez une nouvelle classe que vous prévoyez d’autoriser une seule instance de votre code, vous pouvez aussi l’écrire en tant que Singleton. Considérez-le comme écrivant une classe plain-jane et en y ajoutant pour faciliter l’exigence d’une seule instanciation. Si vous utilisez la classe de quelqu’un que vous ne pouvez pas modifier (comme mysqli ), vous devriez utiliser une classe statique (même si vous ne préfixez pas sa définition avec le mot-clé).

Les singletons sont plus flexibles, ce qui peut être utile dans les cas où vous souhaitez que la méthode Instance renvoie différentes sous-classes concrètes du type Singleton en fonction d’un contexte.

Les classes statiques ne peuvent pas être transmises comme arguments. des instances d’un singleton peuvent être. Comme mentionné dans d’autres réponses, surveillez les problèmes de threading avec les classes statiques.

rp

Un singleton peut avoir un constructeur et un destructeur. Selon votre langue, le constructeur peut être appelé automatiquement la première fois que votre singleton est utilisé ou jamais si votre singleton n’est pas utilisé du tout. Une classe statique n’aurait pas une telle initialisation automatique.

Une fois qu’une référence à un object singleton est obtenue, elle peut être utilisée comme n’importe quel autre object. Le code client n’a même pas besoin de connaître son utilisation d’un singleton si une référence au singleton est stockée précédemment:

 Foo foo = Foo.getInstance(); doSomeWork(foo); // doSomeWork wont even know Foo is a singleton 

Cela facilite évidemment les choses lorsque vous choisissez de laisser tomber le modèle Singleton en faveur d’un modèle réel, comme l’IoC.

Utilisez le modèle singleton lorsque vous devez calculer quelque chose à l’exécution que vous calculeriez au moment de la compilation, si vous le pouvez, comme les tables de recherche.

Je pense qu’un endroit où Singleton aura plus de sens que la classe statique, c’est quand vous devez construire un pool de ressources coûteuses (comme les connexions aux bases de données). Vous ne seriez pas intéressé par la création du pool si personne ne les utilise (la volonté de classe statique signifie que vous faites le travail coûteux lorsque la classe est chargée).

Un singleton est également une bonne idée si vous souhaitez forcer la mise en cache efficace des données. Par exemple, j’ai une classe qui recherche les définitions dans un document XML. Depuis que l’parsing du document peut prendre un certain temps, j’ai configuré un cache de définitions (j’utilise SoftReferences pour éviter outOfmemeoryErrors). Si la définition souhaitée n’est pas dans le cache, je fais l’parsing syntaxique coûteuse. Sinon, je retourne une copie du cache. Étant donné que plusieurs caches signifieraient que je pourrais avoir à charger la même définition plusieurs fois, je dois avoir un cache statique. J’ai choisi d’implémenter cette classe en tant que singleton afin de pouvoir écrire la classe en utilisant uniquement des membres de données normaux (non statiques). Cela me permet de créer encore une ostéiation de la classe si j’en ai besoin pour une raison quelconque (sérialisation, tests unitaires, etc.)

Singleton est comme un service, comme déjà mentionné. Pro est sa flexibilité. Statique, eh bien, vous avez besoin de pièces statiques pour implémenter Singleton.

Singleton a du code pour prendre soin de l’instanciation de l’object réel, ce qui peut être très utile si vous rencontrez des problèmes de course. Dans une solution statique, vous devrez peut-être gérer des problèmes de course à plusieurs emplacements de code.

Cependant, même si Singleton peut être construit avec des variables statiques, vous pourrez peut-être le comparer à «goto». Cela peut être très utile pour construire d’autres structures, mais vous devez vraiment savoir comment l’utiliser et ne pas en abuser. Par conséquent, la recommandation générale est de restr fidèle à Singleton, et d’utiliser statique si nécessaire.

vérifier également l’autre post: Pourquoi choisir une classe statique sur une implémentation singleton?

référer ceci

résumé:

une. Une règle simple que vous pouvez suivre est que si vous n’avez pas besoin de maintenir l’état, vous pouvez utiliser une classe statique, sinon vous devriez utiliser un singleton.

b. utiliser un Singleton est si c’est un object particulièrement «lourd». Si votre object est volumineux et prend une quantité raisonnable de mémoire, beaucoup d’appels n / w (pool de connexions) ..etc. Pour vous assurer qu’il ne sera pas instancié plusieurs fois. Une classe Singleton aidera à prévenir un tel cas

Lorsque la classe unique nécessite un état. Les singletons maintiennent un état global, contrairement aux classes statiques.

Par exemple, créez une aide autour d’une classe de registre: Si vous avez une hive variable (HKey Current User ou HKEY Local Machine), vous pouvez aller:

 RegistryEditor editor = RegistryEditor.GetInstance(); editor.Hive = LocalMachine 

Maintenant, tous les appels à ce singleton fonctionneront sur la hive de l’ordinateur local. Sinon, en utilisant une classe statique, vous devrez spécifier ce répertoire hive de machine locale ou utiliser une méthode telle que ReadSubkeyFromLocalMachine .