Quand devriez-vous utiliser le modèle singleton au lieu d'une classe statique? [fermé]


85

Nommez les considérations de conception pour décider 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! De plus, chaque intervieweur aime voir des exemples illustratifs. :)


une classe java ne peut pas rendre statique à moins que ce ne soit une classe interne
Harshana

1
Si l'état de l'objet importe, utilisez singleton, sinon utilisez une classe statique.
Levent Divilioglu

Réponses:


80
  • Les singletons peuvent implémenter des interfaces et hériter d'autres classes.
  • Les singletons peuvent être chargés paresseusement. Seulement quand c'est vraiment nécessaire. C'est très pratique si l'initialisation comprend un chargement de ressources coûteux ou des connexions à la base de données.
  • Les singletons offrent un objet réel.
  • Les singletons peuvent être transformés en usine. La gestion des objets en arrière-plan est abstraite, elle est donc mieux maintenable et aboutit à un meilleur code.

2
Jetez également un œil à ce lien: codeofdoom.com/wordpress/2008/04/20/…
Amit

4
"Les singletons peuvent être chargés paresseusement" - en C #, le constructeur statique n'est appelé que la première fois qu'un membre statique est référencé. En PHP, vous pouvez utiliser le chargement automatique pour ne l'exécuter que la première fois que la classe est utilisée.
mpen

Les initialisations statiques Java sont également paresseuses. Pas de points pour les Singletons là-bas.
MikeFHay

13

Que diriez-vous "d'éviter les deux"? Singletons et classes statiques:

  • Peut introduire un état mondial
  • Soyez étroitement couplé à plusieurs autres classes
  • Masquer les dépendances
  • Peut rendre difficile les classes de test unitaire isolées

Au lieu de cela, examinez l' injection de dépendances et l' inversion des bibliothèques de conteneurs de contrôle . Plusieurs bibliothèques IoC se chargeront de 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 #.)


1
Petites nits: les classes singleton sont compatibles avec les techniques d'injection de dépendances (il suffit de les injecter dans leurs classes dépendantes et elles n'ont pas besoin de coder en dur) - cela permet de se moquer et de tester de manière isolée. Ils constituent également un modèle de conception valide pour la gestion des ressources connues pour être limitées à l'échelle de la plate-forme. (L'exemple classique est celui des imprimantes qui n'ont pas de gestion des
conflits

@cdleary - d'accord; cependant, l'implémentation classique laisse souvent Singleton.getInstance () dans toute la base de code. Des «singletons» pour gérer les ressources, les caches, etc. peuvent être implémentés avec les frameworks POCO / POJO et IoC Container qui prennent en charge la gestion de la durée de vie (enregistrez le type comme durée de vie du conteneur et chaque résolution obtiendra la même instance).
TrueWill

9
Si vous voulez donner à vos Singletons un enterrement approprié, rendez-vous sur singletonfuneralservice.com
TrueWill

1
Hide DependenciesLittle sideinfo sur ce point: Vous pouvez implémenter le modèle Inversion of Control par exemple en utilisant Ninject . Cela vous permet de n'utiliser qu'une seule instance d'un type en la liant à a SingletonScope, ce qui signifie qu'elle injectera toujours la même instance, mais que la classe ne sera pas singleton.
LuckyLikey

8

Je dirais que la seule différence est la syntaxe: MySingleton.Current.Whatever () vs MySingleton.Whatever (). L'État, comme David l'a mentionné, 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 en .Net, elles ne le peuvent pas). Donc, si vous avez besoin de cette fonctionnalité, vous devez utiliser un singleton.


7

Une de mes discussions préférées sur ce problème est ici (site d'origine en panne, 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 renvoyer différentes sous-classes
  • cela peut aboutir à une application plus maintenable

5

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 mieux.

/**
 * 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é plus tard pour faire du pooling, des instances locales de thread, etc.

public static class LessUgly {
       private static Hashtable<String,LessUgly> session;
       private static FIFO<LessUgly> freePool = new FIFO<LessUgly>();
       private static final POOL_SIZE=5;
       private int count;

       private LessUgly(){
       }

       public static synchronized getInstance(){
         if( session==null){
            session = new Hashtable<String,LessUgly>(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 distribution indirecte.

Vous pouvez obtenir l'instance et la transmettre à une fonction en tant qu'argument. Cela permet au code d'être dirigé vers le «bon» singleton. Nous savons que vous n'en aurez besoin que d'un seul ... jusqu'à ce que vous n'en ayez pas besoin.

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


4

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

ObjectFactory.getInstance().makeObject();

La fabrique d'objets est un objet qui effectue un service spécifique.

En revanche, une classe pleine de méthodes statiques est une collection d'actions que vous voudrez peut-être effectuer, organisées dans un groupe lié (la classe). Par exemple

StringUtils.reverseString("Hello");
StringUtils.concat("Hello", "World");

L'exemple StringUtils ici est une collection de fonctionnalités qui peuvent être appliquées n'importe où. L'objet de fabrique singleton est un type d'objet spécifique avec une responsabilité claire qui peut être créée et transmise si nécessaire.


4

Les classes statiques sont instanciées au moment de l'exécution. Cela peut prendre du temps. Les singletons ne peuvent être instanciés qu'en cas de besoin.


13
Les singletons sont également instanciés à l'exécution ...
récursif

1
@recursive: l'instanciation de singleton peut être contrôlée.
Nikit Batale

3
peut-être qu'un meilleur mot serait initialisation (plutôt que instanciation)
Marlon

3

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();

En fait, vous devriez traiter le singleton comme un simple objet . 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'objet est un singleton et doit traiter l'objet comme un simple objet.

L'objet 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'objet ne devraient pas avoir à savoir si l'objet est un singleton ou non.


2

Si par "classe statique" vous entendez une classe qui n'a que des variables statiques, elles peuvent en fait maintenir l'état. Je crois comprendre 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 fonctionneront tous les deux de la même manière en ce qui concerne le code client.


2
Les singletons sont eux-mêmes des objets -> ils peuvent être passés comme arguments.
Christian Klauser

2

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


1

Les singletons ne doivent jamais être utilisés (sauf si vous considérez une classe sans état mutable comme un singleton). Les "classes statiques" ne devraient avoir aucun état mutable, à part peut-être des caches thread-safe et autres.

Presque tous les exemples de singleton montrent comment ne pas le faire.


4
Qu'en est-il des classes de gestionnaires contrôlant les ressources matérielles? Qu'en est-il des classes de fichiers journaux?
RJFalconer

0

Si un singleton est quelque chose dont vous pouvez vous débarrasser, pour nettoyer après lui, vous pouvez le considérer quand il s'agit d'une ressource limitée (c'est-à-dire seulement 1) dont vous n'avez pas besoin tout le temps, et que vous avez une sorte de mémoire ou coût des ressources lorsqu'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 statiques.

Le code, cependant, sera un peu le même dans les deux cas, donc si vous avez des raisons plus spécifiques de demander, vous devriez peut-être élaborer.


0

Les deux peuvent être assez similaires, mais rappelez-vous que le vrai Singleton doit lui-même être instancié (accordé, une fois) puis servi. Une classe de base de données PHP qui renvoie une instance de mysqlin'est pas vraiment un Singleton (comme certains l'appellent), car elle renvoie une instance d'une autre classe, pas une instance de la classe qui a l'instance en tant que membre statique.

Donc, si vous écrivez une nouvelle classe dont vous prévoyez de n'autoriser qu'une seule instance dans votre code, vous pouvez aussi bien l'écrire en tant que Singleton. Considérez cela comme l'écriture d'une classe ordinaire et l'ajout à celle-ci pour faciliter l'exigence d'instanciation unique. Si vous utilisez la classe de quelqu'un d'autre que vous ne pouvez pas modifier (comme mysqli), vous devriez utiliser une classe statique (même si vous ne parvenez pas à préfixer sa définition avec le mot-clé).


0

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.


0

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

rp


0

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

Une fois qu'une référence à un objet singleton est obtenue, elle peut être utilisée comme n'importe quel autre objet. Le code client n'a même pas besoin de savoir qu'il utilise un singleton si une référence au singleton est stockée plus tôt:

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

Cela facilite évidemment les choses lorsque vous choisissez d'abandonner le modèle Singleton au profit d'un modèle réel, comme IoC.


0

Utilisez le modèle singleton lorsque vous avez besoin de calculer quelque chose au moment de l'exécution que vous calculeriez au moment de la compilation si vous le pouviez, comme des tables de recherche.


0

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


0

Un singleton est également une bonne idée si vous souhaitez forcer une mise en cache efficace des données. par exemple, j'ai une classe qui recherche des définitions dans un document xml. Puisque l'analyse du document peut prendre un certain temps, j'ai mis en place 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'analyse XML coûteuse. Sinon, je renvoie une copie du cache. Étant donné que le fait d'avoir plusieurs caches signifierait que je pourrais encore devoir charger la même définition plusieurs fois, j'ai besoin d'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 istantiation de la classe si j'en ai besoin pour une raison quelconque (sérialisation, test unitaire, etc.)


0

Singleton est comme un service, comme déjà mentionné. Le pro est sa flexibilité. Statique, eh bien, vous avez besoin de certaines parties statiques pour implémenter Singleton.

Singleton a du code pour s'occuper de l'instanciation de l'objet réel, ce qui peut être d'une grande aide 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, comme Singleton peut être construit avec des variables statiques, vous pourrez peut-être le comparer avec '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 s'en tenir à Singleton et d'utiliser statique si nécessaire.

Vérifiez également l'autre article: Pourquoi choisir une classe statique plutôt qu'une implémentation singleton?


0

référer ceci

sommaire:

une. Une règle de base simple que vous pouvez suivre est que si elle n'a pas besoin de maintenir l'état, vous pouvez utiliser une classe statique, sinon vous devriez utiliser un Singleton.

b. utilisez un Singleton s'il s'agit d'un objet particulièrement «lourd». Si votre objet est volumineux et occupe 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 à éviter qu'un tel cas ne se produise


-1

Lorsque la classe unique a besoin d'un état. Les singletons conservent un état global, contrairement aux classes statiques.

Par exemple, créer une aide autour d'une classe de registre: si vous avez une ruche modifiable (HKey Current User vs HKEY Local Machine), vous pouvez aller:

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

Désormais, tout autre appel à ce singleton fonctionnera sur la ruche de la machine locale. Sinon, en utilisant une classe statique, vous devrez spécifier que la machine locale ruche tous les éléments, ou avoir une méthode comme ReadSubkeyFromLocalMachine.


1
Je dirais contre l'utilisation d'un Singleton de cette manière ... Il est très dangereux de garder les états en suspens, car le prochain appelant pourrait oublier de définir la ruche et écrire dans le registre dans la mauvaise ruche ... :-( C'est probablement un exemple d'utilisation abusive qui fait que les gens pensent que les singletons sont mauvais.
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.