Différence entre static et singleton

Différence entre static et singleton - Java - Programmation

Marsh Posté le 10-08-2007 à 10:24:45    

:hello:  
 
Quelle est la différence entre une classe static et singleton pour gérer un objet unique ?

Reply

Marsh Posté le 10-08-2007 à 10:24:45   

Reply

Marsh Posté le 10-08-2007 à 10:49:01    

Ta classe non-singleton est déclarée statique en membre d'une autre classe, ce qui fait qu'on pourrait avec des versions non statiques de ta classe, ce qui peut poser souci, si l'interet d'avoir une instance unique de ta classe est par exemple d'acceder de manière unique à un fichier ou un matériel.


---------------
Töp of the plöp
Reply

Marsh Posté le 10-08-2007 à 13:44:36    

Fonctionnellement, la plupart du temps, il n'y a pas de différences entre faire un singleton et une "classe static" (cad une classe qui n'a que des attributs et méthodes static)
 
Mais il y a des choses que tu ne peux faire qu'avec une instance singleton (sérialization, ajout dans une collection).
 
Je pense que c'est plus propre et plus évolutif de faire un singleton

Reply

Marsh Posté le 10-08-2007 à 13:54:10    

Bidem a écrit :

Fonctionnellement, la plupart du temps, il n'y a pas de différences entre faire un singleton et une "classe static" (cad une classe qui n'a que des attributs et méthodes static)
 
Mais il y a des choses que tu ne peux faire qu'avec une instance singleton (sérialization, ajout dans une collection).
 
Je pense que c'est plus propre et plus évolutif de faire un singleton


merci ;)

Reply

Marsh Posté le 10-08-2007 à 14:40:04    

La principale et plus grosse différence c'est qu'un singleton c'est du "lazy evaluation": l'instance n'est créée (et la ressource récupérée) qu'au premier accès, alors qu'avec un static c'est au moment ou le classloader génère la classe.

 

Après, une classe statique c'est infiniment plus simple à utiliser puisqu'il n'y a pas besoin de récupérer l'instance en permanence, et c'est thread-safe par définition contrairement à la majorité des singletons.

Message cité 1 fois
Message édité par masklinn le 10-08-2007 à 14:40:49

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 10-08-2007 à 21:39:35    

Bidem a écrit :

Fonctionnellement, la plupart du temps, il n'y a pas de différences entre faire un singleton et une "classe static" (cad une classe qui n'a que des attributs et méthodes static)
 
Mais il y a des choses que tu ne peux faire qu'avec une instance singleton (sérialization, ajout dans une collection).
 
Je pense que c'est plus propre et plus évolutif de faire un singleton


Parfaitement.  
De plus une classe statique ne te permet pas de disposer de l'héritage au sens objet du terme, c'est à dire l'héritage dynamique (virtual en C++)... ton héritage sera statique.
Une classe statique doit être utilisée pour fournir des méthodes utilitaires, à l'instar de la classe Math de java par exemple.

Reply

Marsh Posté le 10-08-2007 à 21:42:15    

_TT_ a écrit :


Parfaitement.  
De plus une classe statique ne te permet pas de disposer de l'héritage au sens objet du terme, c'est à dire l'héritage dynamique (virtual en C++)... ton héritage sera statique.


Quand je vois à quel point il est difficile de faire un singleton héritable, il n'y a aucune différence à ce niveau.

_TT_ a écrit :

Une classe statique doit être utilisée pour fournir des méthodes utilitaires, à l'instar de la classe Math de java par exemple.


n'importe quoi [:pingouino]


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 11-08-2007 à 00:51:23    


Non pas du tout, mais de liaison statique / dynamique à l'exécution.
 
Si tu as B hérite de A, et m1() est une méthode à la fois dans A et dans B (avec la même signature), si tu manipules un A dans un traitement (qui peut être indifférement un A ou un B), c'est la méthode m1() de l'objet réellement instancié qui est appelée et non pas la méthode de la classe déclarée manipulée :
 
traitement(A monObjet){  
    monObjet.m1()
}
 
Dans le cas d'une liaison dynamique :
Si tu passes un A, on appelera A.m1(), si tu passes un B, on appelera le m1() défini dans B. (cas d'un virtual m1() en C++ )
 
Dans le cas d'une liaison statique :
Que tu passes un A ou un B, on appelera toujours A.m1(). (cas d'un m1() en C++ )
 
Donc avec un singleton, c'est bien la liaison dynamique qui s'opère, vu qu'il est un objet instancié, et qu'en JAVA toutes les liaisons d'instances sont dynamiques.
Avec une classe statique, tu ne peux pas avoir ce genre de traitement, aucun objet n'étant instancié donc passable en paramètre.. A moins que tu te débrouilles en passant un paramètre de type Class (ce qui est très moche), et que tu appelles ta méthode sur ce paramètre , ce qui fonctionnerait dans ce cas en liaison statique.
 
Pour résumer, le singleton te laisse dans la philosophie objet ( possibilité d'implémenter des interfaces, d'avoir la liaison dynamique, etc etc...), alors qu'une classe statique n'est jamais instanciée et qu'elle te prive par conséquent de ces mécanismes.
 

masklinn a écrit :


Quand je vois à quel point il est difficile de faire un singleton héritable, il n'y a aucune différence à ce niveau.


Ah bon, c'est si difficile de faire un singleton héritable pour toi? Et le constructeur en protected? Ou bien encore pas de mot clé de visibilité, càd visibilité de package ?
Je ne vois pas en quoi c'est si difficile, et surtout, que tu dises qu'il n'y a pas de différence à ce niveau, alors que la liaison est dans un cas statique et dans l'autre dynamique. Ca n'a aucun lien avec le fait que ça soit difficile ou non.
 

masklinn a écrit :


n'importe quoi [:pingouino]


Heu excuse-moi, pourquoi être si catégoriquement contradicteur ? Une classe statique te permet finalement de définir des traitement procéduriaux, que tu détaches de la phylosophie "objet". C'est le cas de méthodes dites utilitaires.. (du genre Math.cos(), Math.sin()... ). Ce qui ne les empèche pas de manipuler elles mêmes des objets. Par exemple Collections.sort(maCollection).
Pour ces méthodes, il n'y a aucun intérêt à avoir une instance, c'est presque comme si tu définissais des opérateurs. Un singleton lui, peut par exemple être un état (comme dans le design pattern "state" ), être référencé par d'autres objets ce qui justifie son existence en tant qu'instance. Si tu n'as pas cerné ce que je voulais dire, demande-moi plutôt de détailler ou de dire que tu n'es pas d'accord et surtout pourquoi, car nier quelquechose sans explication ne fait avancer en rien la discussion, surtout accompagné d'un smiley de ce genre.
 

masklinn a écrit :

Laprincipale et plus grosse différence c'est qu'un singleton c'est du"lazy evaluation": l'instance n'est créée (et la ressource récupérée) qu'au premier accès, alors qu'avec un static c'est au moment ou leclassloader génère la classe.
 
Après, une classe statique c'estinfiniment plus simple à utiliser puisqu'il n'y a pas besoin derécupérer l'instance en permanence, et c'est thread-safe par définition contrairement à la majorité des singletons.


C'est totalement faux. Ce n'est pas plus thread-safe qu'une instance... tant que tu n'auras pas utilisé les mécanismes de synchronisation.
Si tu veux faire du thread-safe, tu te contentes d'utiliser correctement la synchronisation et les verrous, et ça n'a aucun rapport avec le fait que tu manipules un singleton ou une classe statique. Ta classe statique sera thread-safe si tu définis tes méthodes ou des blocs en "synchronized", avec prise et lacher de verrou.
 
Je te conseille d'aller jeter un oeil ici pour mieux comprendre pourquoi ton affirmation Static => Thread Safe est fausse :
 http://www.javaworld.com/javaworld [...] dsafe.html
http://java.sun.com/docs/books/tut [...] l/threads/
http://forum.java.sun.com/thread.j [...] tstart=105 (voir à partir du 4ème post)
 
Merci de valider ce que tu dis avant de sortir des âneries pareilles.
Et si tu n'es pas sûr ce que tu dis, utilise "je pense que".

Message cité 3 fois
Message édité par _TT_ le 11-08-2007 à 12:11:32
Reply

Marsh Posté le 11-08-2007 à 12:35:23    

_TT_ a écrit :


Ah bon, c'est si difficile de faire un singleton héritable pour toi? Et le constructeur en protected? Ou bien encore pas de mot clé de visibilité, càd visibilité de package ?


Si tu penses que c'est suffisant de mettre un constructeur en protected t'as jamais réellement songé au problème des singletons hérités.

 

Hint: les classes héritées doivent-elles être des singletons ou non? Si non, pourquoi la classe parent est-elle un singleton? Si oui, la singletonisation de ton singleton se fait elle par sous-classe (quel est l'intérêt d'en faire des singletons si tu peux en avoir plusieurs dans ton système? Après tout des classes héritées doivent être "drop-in replaceable", si remplacer une sous-classe de ton singleton par une autre génère une nouvelle instance parallèle à l'ancienne, est-ce encore un singleton?) ou sur l'intégralité des singletons de ton arbre d'héritage (et dans ce cas comment le gérer à part%

Message cité 1 fois
Message édité par masklinn le 11-08-2007 à 12:41:48

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 11-08-2007 à 13:06:05    

masklinn a écrit :


Si tu penses que c'est suffisant de mettre un constructeur en protected t'as jamais réellement songé au problème des singletons hérités.
 
Hint: les classes héritées doivent-elles être des singletons ou non? Si non, pourquoi la classe parent est-elle un singleton? Si oui, la singletonisation de ton singleton se fait elle par sous-classe (quel est l'intérêt d'en faire des singletons si tu peux en avoir plusieurs dans ton système? Après tout des classes héritées doivent être "drop-in replaceable", si remplacer une sous-classe de ton singleton par une autre génère une nouvelle instance parallèle à l'ancienne, est-ce encore un singleton?) ou sur l'intégralité des singletons de ton arbre d'héritage (et dans ce cas comment le gérer à part%


 
Encore une ânerie. En te lisant, on voit que tu n'as pas compris ce qu'était l'héritage. L'héritage doit se comprendre au niveau de la classe (c'est à dire du modèle) et non pas au niveau de l'objet.
 
Par héritage, on définit une classe basée sur les mêmes caractéristiques qu'une autre, et pouvant bien sûr les compéter.
En d'autres termes, on définit un modèle reprenant les caractéristiques d'un autre modèle, mais les complétant. On n'est pas encore au niveau de l'objet.
 
Si tes 2 classes sont des singletons, alors, tu peux avoir une instance, d'une, et une instance de l'autre.
Ce ne sont pas les même, donc ce n'est absolument pas une instance parallèle... Donc ca reste tout à fait compatible avec le concept du singleton..
 
Et même si tu fais :
A monA = A.getInstance();
B monB = B.getInstance();
monA = monB
monA.m1(), tu appeleras la méthode définie dans B.
 
Les instances de A et de B resteront uniques, et n'auront jms d'instance parallèle.
 
Exemple pratique :
 
Dans ma maison je veux avoir :
- une unique table standard
- une unique table à roulette
- une méthode de nettoyage
 
Je définis une classe Table, singleton, qui définit les caractéristiques d'une table (longueur, largeur, hauteur..), ainsi qu'une méthode nettoyage().
Je définis une classe TableARoulettes, qui elle aussi a une longueur, largeur, hauteur, donc je me dis que je peux simplement hériter de la classe Table, mais rajouter une propriété "taille des roulettes". Je peux également surcharger la méthode nettoyage(), pour nettoyer aussi les roulettes.
 
J'instancie ma Table, et ma TableARoulettes.
 
Dans ma maison j'aurai bien une unique Table, une unique TableARoulettes, et même si les 2 tables sont des objets disposant par exemple de méthodes communes, comme "nettoyer()", et que je veux lancer un traitement de nettoyage sur les 2 tables l'une après l'autre par une fonction :
 
traitementDeNettoyage(Table uneTable){
   uneTable.nettoyer()
}
 
je pourrai lui passer à la fois mon instance de ma Table et mon instance de ma TableARoulette.
 
Mais j'ai toujours une seule instance de chaque classe. J'espère que c'est plus clair.

Message cité 1 fois
Message édité par _TT_ le 11-08-2007 à 14:45:08
Reply

Marsh Posté le 11-08-2007 à 13:06:05   

Reply

Marsh Posté le 11-08-2007 à 14:41:10    


 
Si tu veux un rapide résumé sur le polymorphisme, pas de problème : Déjà, il existe plusieurs types de polymorphismes :
- le polymorphisme de paramétrage (généricité)
- le polymorphisme adhoc (par exemple une surcharge d'opérateurs, positionnés dans des classes qui n'ont aucun rapport entre-elles)
- le polymorphisme d'héritage qui consiste à redéfinir ou spécialiser.
 
Dans notre cas, on parle de liaison dynamique/statique, c'est un concept lié au polymorphisme d'héritage mais ce n'est pas la même chose. (le polymorphisme d'héritage est le contexte du concept de liaison statique/dynamique).
 
Mais je reconnais que j'aurais du écrire "Non pas tout à fait", au lieu de "Non pas du tout"  :)


Message édité par _TT_ le 11-08-2007 à 15:03:04
Reply

Marsh Posté le 18-09-2007 à 17:21:42    

Un singleton est une instance d'une classe qui a la propriété d'etre unique.
Le pattern est une protection contre les erreurs de programmation qui permet d'éviter de construire plusieurs instances.. quand tu en veux toujours une seule et toujours la même.  
Le fait que ce soit une instance permet de la manipuler (dans des listes, dans d'autres objets, l'utiliser dans d'autres modules (via le reseau,...).
 
 
Si tu ne vois pas de différences avec les classes statique, c'est que tu n'a pas besoin de singleton dans ton programme.

Reply

Marsh Posté le 13-01-2008 à 22:21:49    

Pour moi la classe statique est un anti-pattern, mais bon j'dis ça, j'dis rien...
EDIT: sauf pour les utilitaires Math Collections ou Arrays etc... comme dit plus haut

Message cité 1 fois
Message édité par bugsan le 13-01-2008 à 22:23:44
Reply

Marsh Posté le 16-01-2008 à 16:10:50    

Ce n'est pas le seul anti-pattern. L'initialisation retardée du singleton en environnement multi-thread, que mentionnait Masklinn, en est un autre.  
 
C'est ce qu'on appelle en anglais le "double-check locking", et ça provoque, en Java comme en C ou C++, des bugs d'initialisation très subtils et très difficiles à déboguer (du genre double instance, ou utilisation d'une instance partiellement initialisée).
 
En Java, il vaut beaucoup mieux initialiser l'instance en même temps au moment de charger la classe du singleton. Le code est plus lisible et c'est 100% thread-safe (car le chargement d'une classe par le ClassLoader est fait dans un bloc synchronized par la JVM).

Reply

Marsh Posté le 16-01-2008 à 16:23:59    

Juste comme ça, parceque niveau sémantique je suis nul...
 
Une classe "singleton", c'est bien une classe static avec un constructeur ? (je parle pour le C#, je ne connais pas Java) histoire que je m'y retrouve dans vos notions :D

Reply

Marsh Posté le 16-01-2008 à 16:29:06    

bugsan a écrit :

Pour moi la classe statique est un anti-pattern, mais bon j'dis ça, j'dis rien...
EDIT: sauf pour les utilitaires Math Collections ou Arrays etc... comme dit plus haut


La classe statique est un anti-pattern sauf quand ça l'est pas, super [:bien]

 

Ben pour moi, le singleton est un anti-pattern... point barre, pas de discussion ou de cas particulier [:dawa]

MagicBuzz a écrit :

Juste comme ça, parceque niveau sémantique je suis nul...

 

Une classe "singleton", c'est bien une classe static avec un constructeur ? (je parle pour le C#, je ne connais pas Java) histoire que je m'y retrouve dans vos notions :D


http://en.wikipedia.org/wiki/Singleton_pattern
http://c2.com/cgi/wiki?SingletonPattern

 

À noter qu'implémenter un singleton de cette manière est sûr de se vautrer si on est en multithreaded :o

Message cité 1 fois
Message édité par masklinn le 16-01-2008 à 16:30:54

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 16-01-2008 à 16:34:54    


Une registry de quoi? Et pourquoi ça serait un singleton?

 

edit: et à part ça, http://steve.yegge.googlepages.com [...] red-stupid
et je conseille aussi http://c2.com/cgi/wiki?search=singleton

Message cité 1 fois
Message édité par masklinn le 16-01-2008 à 16:38:57

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 16-01-2008 à 16:41:43    

Ah oui, ça me revient.
 
Alors donc, histoire que je m'en souvienne une bonne fois pour toute, c'est quoi ce type de classe ?
 
=> La classe n'est pas statique, mais tous les éléments à l'intérieur le son, y compris le contructeur. Et comme un singleton, une fois appelé une première fois, tous les appels suivants feront appel à la même instance.

Code :
  1. public class Class1
  2.    {
  3.        private static string coin;
  4.  
  5.        static Class1()
  6.        {
  7.            coin = "plop";
  8.        }
  9.  
  10.        public static string getVal()
  11.        {
  12.            return coin;
  13.        }
  14.  
  15.        public static void setVal(string val)
  16.        {
  17.            coin = val;
  18.        }
  19.    }


 
PS : Et accessoirement... Ca revient pas au même ? Moi j'utilise tout le temps le code ci-dessus pour accéder par exemple à un fichier INI ou la BDR, ou si je dois gérer un contexte, etc...
En fait c'est comme si j'avais une instance unique déclarée en global si on se réfère à la vieille programmation.
 
(PS² : Je sais bien qu'on est en Java là, donc ne m'explosez pas si y'a pas d'équivalent en Java, c'est juste que là je me demande si c'est pas plus proche du singleton qu'une classe statique... A moins que ce soit ça que l'auteur appelle une classe static ? -mais pourtant là c'est pas une classe static puisqu'elle n'est pas elle-même statique :o-)


Message édité par MagicBuzz le 16-01-2008 à 16:53:35
Reply

Marsh Posté le 16-01-2008 à 17:35:20    

-- Ok, donc d'après ce que j'ai relu, c'est bien ça que vous appelez une classe "statique" (pourtant c'en est pas une mais bon)
 

Bidem a écrit :

Mais il y a des choses que tu ne peux faire qu'avec une instance singleton (sérialization, ajout dans une collection).


Comme ça tu ne peux pas ajouter dans une collection avec une classe "statique" ?
Tu veux dire que la classe ne peux pas travailler avec des collection ? Ou que tu ne peux pas stocker d'instance de ta classe dans une collection ? (ce qui est logique puisque t'as pas d'instance à proprement parler)
 
Parceque si c'est le premier cas, je ne comprends pas, moi ça marche très bien :??:

Reply

Marsh Posté le 17-01-2008 à 19:19:15    


 :jap: Article extremement interessant, merci !

Reply

Marsh Posté le 18-01-2008 à 14:03:49    

Définition d'un singleton : instance unique d'une classe.
Le constructeur privé (ou protégé) et l'instance unique déclarée statique dans la classe est un moyen d'obtenir un singleton. Mais pas sa définition.
Normalement, le mot "singleton" devrait vous rappeler des souvenirs de maths, où on l'utilisait dans le sens d' "ensemble qui ne contient qu'un seul élément". Exemple de classe à singleton : java.lang.Runtime
 
Par ailleurs, la notion de "classe statique" n'a pas de sens.
Un certain nombre d'entre vous semble utiliser cette expression dans le sens de "classe utilitaire", qui est une classe dont le constructeur est privé (ou protégé, à la rigueur) et dont toutes les méthodes sont des méthodes de classe (donc statiques en Java). Exemple de classe utilitaire : java.lang.Math

Reply

Marsh Posté le 18-01-2008 à 14:12:44    

BifaceMcLeOD a écrit :

Un certain nombre d'entre vous semble utiliser cette expression dans le sens de "classe utilitaire", qui est une classe dont le constructeur est privé (ou protégé, à la rigueur) et dont toutes les méthodes sont des méthodes de classe (donc statiques en Java). Exemple de classe utilitaire : java.lang.Math


Le constructeur n'a aucune importance, c'est simplement utilisé pour décrire une classe dont toutes les méthodes sont statiques. Ce qui serait symbolisé par un module si Java avait des modules de première classe.


Message édité par masklinn le 18-01-2008 à 14:13:49

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 18-01-2008 à 14:41:13    

BifaceMcLeOD a écrit :

Par ailleurs, la notion de "classe statique" n'a pas de sens.
Un certain nombre d'entre vous semble utiliser cette expression dans le sens de "classe utilitaire", qui est une classe dont le constructeur est privé (ou protégé, à la rigueur) et dont toutes les méthodes sont des méthodes de classe (donc statiques en Java). Exemple de classe utilitaire : java.lang.Math


Ben en fait, justement, je confond la "notion de classe statique" avec une "vraie classe statique"...
 
Parcequ'une "vraie classe statique" :

Code :
  1. static class maclasse {}


Ca ne peut avoir ni constructeur, ni méthode non statique, ni le moindre appel à la moindre référence d'une instance de la classe (mot clé "this" interdit).
Et ce genre de classe, c'est effectivement uniquement voué à servir de lib "toolbox" tel que la class "Math" par exemple.
 
Alors que la "notion de classe statique", c'est effectivement une classe non statique, avec un constructeur privé et des méthodes statiques... qui permettent cette fois d'utiliser une référence à l'unique instance persistante que crée ce constructeur...
Et ce genre de classe, c'est pas du tout une toolbox, mais pour moi une classe de contexte global, qui peut servir par exemple à centraliser tous les appels à un fichier de configuration, etc. tout en garantissant qu'on ne fait jamais d'accès concurrents (une seule instance possible, et multi-threading impossible si je ne me trompe pas)
 
Je trouve que cette dénomination porte vraiment à confusion...

Reply

Marsh Posté le 18-01-2008 à 14:44:43    

MagicBuzz a écrit :


Ben en fait, justement, je confond la "notion de classe statique" avec une "vraie classe statique"...
 
[...]
 
Je trouve que cette dénomination porte vraiment à confusion...


Pas du tout, c'est juste que dans .Net ça a été formalisé pour toutes les classes alors qu'en Java la formalisation n'existe que pour les inner classes (il n'est pas possible de déclarer "static class Foo" à la racine d'un fichier, donc).
 
En dehors de ça, l'expression a le même sens en Java et en C#.
 

MagicBuzz a écrit :

qui permettent cette fois d'utiliser une référence à l'unique instance persistante que crée ce constructeur...


Non, c'est pas une classe statique ça.


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 18-01-2008 à 14:55:51    

masklinn a écrit :


Pas du tout, c'est juste que dans .Net ça a été formalisé pour toutes les classes alors qu'en Java la formalisation n'existe que pour les inner classes (il n'est pas possible de déclarer "static class Foo" à la racine d'un fichier, donc).
 
En dehors de ça, l'expression a le même sens en Java et en C#.


D'accord. Mais alors je ne pige pas trop la question du topic : la question de différence entre singleton et classe static ne se pose même pas ! le singleton travaille sur une instance, donc un objet qui vit au fil du temps, tandis que la classe statique ne travaille pas sur une instance, et donc produira toujours le même effet à tout instant (enfin, je me comprends, ça veut pas dire qu'une classe statique est déterministique hein !)
 

masklinn a écrit :

Non, c'est pas une classe statique ça.


d'accord :jap:
et alors donc, ça s'appelle comme ce bignou (j'ai posté un exemple complet quelques posts en arrière)
et dans ce cas, quelle est la différence avec le singleton (parceque là, en revanche, mise à part que la méthode "pas singleton" est super plus simple à coder, je ne vois pas trop de différence dans l'emploi ensuite...) :??:

Reply

Marsh Posté le 18-01-2008 à 15:03:28    

MagicBuzz a écrit :


D'accord. Mais alors je ne pige pas trop la question du topic : la question de différence entre singleton et classe static ne se pose même pas ! le singleton travaille sur une instance, donc un objet qui vit au fil du temps, tandis que la classe statique ne travaille pas sur une instance, et donc produira toujours le même effet à tout instant


Une classe statique peut très facilement avoir des données associées (un état) en plus des méthodes statiques. Ce sont simplements des membres statiques mutables de la classe.

 

Donc une classe statique peut également être un objet qui vit au fil du temps [:spamafote]

 

D'ailleurs, y compris dans java (même si la majorité du truc est planqué et inaccessible), une classe est bien une instance de quelque chose d'autre (une métaclasse, dans les langages qui l'exposent genre Common Lisp, Python ou Ruby) [:spamafote]

 

La seule vraie différence fondamentale entre un singleton et une classe statique, c'est le moment de l'instanciation des données stockées: à la création de la classe pour une classe statique (donc soit au chargement du classloader soit à la première référence à la classe), et à la première tentative d'obtention d'une instance pour le singleton.

 
MagicBuzz a écrit :


d'accord :jap:
et alors donc, ça s'appelle comme ce bignou (j'ai posté un exemple complet quelques posts en arrière)
et dans ce cas, quelle est la différence avec le singleton (parceque là, en revanche, mise à part que la méthode "pas singleton" est super plus simple à coder, je ne vois pas trop de différence dans l'emploi ensuite...) :??:


Ce que tu as posté plus tôt correspond à une classe statique en Java: tout ce qui est à l'intérieur (membres et méthodes) est statique [:spamafote]

 

edit: ah non, j'ai regardé d'un peu plus près, faut dégager le constructeur. Je ne suis même pas sûr qu'il soit possible de déclarer un constructeur comme étant static en java. Et je vois pas quel intérêt ça pourrait bien avoir de toute façon.
re-edit: quoique, java a des Static Blocks, si ça se comporte de la même manière (c'est juste un boût de code exécuté quand la classe est chargée par le ClassLoader) je vois à quoi ça peut servir, mais il faut quand même dégager le constructeur, et le remplacer par un static block.

 

Donc pas de différence si ce n'est, comme je l'ai dit un peu plus tôt, le moment de l'instanciation


Message édité par masklinn le 18-01-2008 à 15:06:32

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 18-01-2008 à 16:31:06    

Ben l'intérêt du truc par exemple, j'ai un fichier ini.
Afin d'éviter d'écrire des informations inconsistantes dedans, je l'ouvre en mode exclusif à l'ouverture du programme.
Et afin d'éviter d'avoir des problèmes d'accès d'une fonction à l'autre de mon programme, je veux travailler avec une seul instance, histoire de ne pas m'emmerder.
 
Deplus, parceque j'ai énormément d'accès à faire dans ce fichier régulièrement, je veux travailler non pas directement dans le fichier, mais dans une collection de propriétés, et cette dernière devra se flusher automatiquement lorsque je quite le programme, sans que je doive me soucier partout dans mon code de comment faire.
 
=> Je crée donc cette classe non statique, mais avec des méthodes statiques.
=> Dans le constructeur static et privé, j'ouvre le fichier INI, et je recopie toutes les clés dans une collection.
=> Des méthodes statiques permettent de manipuler les données dans ma collection
=> Le destructeur (static lui aussi) flush des modifications effectuées dans le fichier, puis ferme le handle
 
Ainsi, à tout endroit dans mon code, j'ai juste à appeler par exemple :
 

Code :
  1. string maval = IniFile.GetStringValue("keyname" );
  2. IniFile.SetStringValue("keyname", maval);


 
Sans jamais me soucier de la façon dont j'obtiens ou enregistre ce qu'il y a dans cette lib.
 
Ici, un exemple que je viens de tester (j'ai eu un doute subit à propos du destructeur dans un tel type de classe :D) et qui marche correctement :D
 

Code :
  1. using System;
  2. using System.IO;
  3. using System.Text;
  4.  
  5. namespace Test
  6. {
  7.    class testfile
  8.    {
  9.        static FileStream handle;
  10.  
  11.        static testfile()
  12.        {
  13.            handle = File.Open("c:\\in\\grmpf.txt", FileMode.OpenOrCreate, FileAccess.Create, FileShare.None);
  14.        }
  15.  
  16.        ~testfile()
  17.        {
  18.            handle.Close();
  19.        }
  20.  
  21.        public static void write(string val)
  22.        {
  23.            byte[] buff = Encoding.UTF8.GetBytes(val);
  24.            handle.Write(buff, 0, buff.Length);
  25.        }
  26.    }
  27. }
  28.  
  29.        private void Form1_Click(object sender, EventArgs e)
  30.        {
  31.            testfile.write("plop" );
  32.            testfile.write("grmpf" );
  33.        }


 
PS : Sinon, j'ai collé un appel à cette classe sur le handler du click de ma form principale. Contrairement à ce que tu sembles dire, le fichier n'est créé que lorsque je clique sur la form (et donc que je fais mon premier appel). Le constructeur n'est donc appelé qu'au premier appel.
 
Par contre, comme prévu, le fichier n'est pas écrasé tant que je ne rédémarre pas l'application, signe que le constructeur n'est appelé qu'au premier appel, et que l'instance reste donc bien vivante tout au long de la vie du programme ensuite.
 
Au final, donc, je trouve cette méthode bien plus sympatique que le singleton (si en plus c'est équivalent...) car on n'a pas à se soucier de coder et maintenir les mécanismes de singleton :)
 
ps : ceci dit, maintenant je me sauve de la cat java, parceque là je parle de C#, c'est juste le titre qui topic qui m'avait interpellé


Message édité par MagicBuzz le 18-01-2008 à 17:02:19
Reply

Marsh Posté le 20-01-2008 à 19:20:55    

Je maintiens ce que je disais : au niveau de la théorie objet, une "classe statique", ça n'a pas vraiment de sens, si "static" signifie "travaille au niveau méta" (c'est comme ça que le mot-clé fonctionne en Java pour les attributs, les méthodes et les classes internes : le membre appartient à la méta-instance, autremet dit la classe, plutôt qu'à l'instance elle-même). Et pour Java, ça n'a pas plus de sens (exception faite des classes internes, dont les instances ont ainsi une référence sur l'instance ou la classe englobante qui les a créées).
 
Par ailleurs, en Java, les constructeurs ne s'appliquent qu'aux instances. Il n'y a pas de "constructeur de classe", au sens strict. Le bloc de code statique  ("static { .... } " ) permet cependant d'exécuter des instructions au moment de charger une classe. Tout comme un bloc de code non statique permet d'exécuter des instructions au moment de créer une instance (en pratique, les instructions du bloc non statique sont exécutées au début de chaque constructeur).
 
Enfin, dans une classe utilitaire (classe sans attributs - sauf constantes éventuelles - et composée exclusivement de méthodes statiques), il est recommandé d'avoir un constructeur non public. Simplement pour garantir que l'utilisateur de cette classe n'en créera pas d'instance (instance dont on ne pourrait de toute façon pas faire grand chose).
 
MagicBuzz> Ce que tu décris dans ton dernier post (classe avec des données statiques, dans ton exemple "testfile" ) est fonctionnellement un singleton. Très franchement, je trouve cette écriture moins propre que celle d'un singleton explicite (précisément parce qu'il s'agit d'un singleton qui ne dit pas son nom : principe de moindre surprise). En plus, l'écriture risque plus délicate pour rendre ton code thread-safe (en gros, il faut poser le verrou sur la classe elle-même, donc l'instance de la classe Class, plutôt que sur l'instance singleton).

Reply

Marsh Posté le 01-02-2008 à 13:06:19    


 
Attention ici, getInstance() n'est PAS thread-safe si on l'écrit comme ça: entre le test de nullité de la référence "instance" et son initialisation, il y a un délai qui peut provoquer une double instanciation, et donc deux threads utilisant des "singletons" distincts.
Normalement on déclare ainsi:
public synchronized getInstance () {...}
(ou bien dans le code de getInstance on se synchronize sur un objet spécifique si on ne veut pas synchronizer sur l'instance Class.
En plus le constructeur est mal nommé, et "instance" devrait être statique. Code correct:

Code :
  1. public class MonSingleton {
  2.   private static MonSingleton instance = null;
  3.   private MonSingleton (){}
  4.   public final synchronized getInstance () {
  5.     if (instance == null)
  6.       instance = new MonSingleton();
  7.     return instance;
  8.   }
  9. }


 
Mais le défaut est justement cette synchronization systématique faite par chaque appel de getInstance(), si on utilise une méthode "lazy" comme ici, ce qui pose des problèmes de performance si getInstance() est très utilisé par de nombreux threads.
 
L'autre solution c'est pas de synchronisation du tout, mais une instanciation (et une synchronization) dès le chargement de la classe (et uniquement à ce moment-là); c'est aussi plus propre car on peut déclarer l'instance comme finale (ce qui interdit de changer par erreur la référence même dans le reste du code privé de la classe singleton) :

Code :
  1. public class MonSingleton {
  2.   private static final MonSingleton instance = new MonSingleton();
  3.   private MonSingleton (){}
  4.   public final getInstance () {
  5.     return instance;
  6.   }
  7. }


 
Note: "getInstance()" est déclarée "final": une classe dérivée ne peut pas surcharger cette méthode pour retourner une instance distincte.
 
Le défaut, si c'en est un, est la durée de vie de l'instance créée: elle persiste en mémoire dans son état actif tant que la classe est référencée par une autre classe active qui la référence, même sans plus jamais l'utiliser. Et aussi, son état n'est pas sérialisable de façon très simple, à cause justement de cette durée de vie qui va lier le singleton (via ses membres) à d'autres objets potentiellement actifs (qui, eux, sont sujets à sérialisation et devraient être associés au singleton dans un certain ordre, alors que le songleton désigne un état global de l'application et non des seuls objets qu'elle manipule).
 
Le modèle singleton est donc une forme rapide de développement. Souvent on doit le faire évoluer vers un pattern de type "Factory" pour lever cette limitation (avec des "singletons paramétrés" ), mais justement le modèle singleton ci-dessus est celui qui permet cette évolution de la façon la plus facile.
 
Dans un pattern "Factory", les paramètres servent à identifier des objets partagés selon certaines caractéristiques qui dépendent du contexte d'utilisation. En général, si les paramètres sont simples ou ont un sensemble de valeurs possible limité, les instances sont stockées dans des attributs simples, sinon on peut utiliser un tableau d'instances si le paramètre est un simple petit entier, ou bien une HashTable. Dans ce cas c'est "getInstance()" qui se synchronize sur la collection (HashMap ou HashTable) d'instances partagées, et crée des instances dynamiquement en fonction des besoins réels. Cette approche est particulièrement utile pour implémenter un cache d'objets non mutables ayant de nombreuses valeurs possibles mais certaines valeurs très fréquemment utilisées, alors que la création d'instances est une opération couteuse (quand les constructeurs sont très complexes et créent un état initial très lourd à initialiser) qu'on veut optimiser autant que possible.
 
Les patterns "Factory" sont très utilisés pour les classes de type GUI (couleurs, polices, styles, etc...) ou dans les classes effectuant de la sérialisation pour améliorer très nettement les performances (cependant là encore, il faut gérer la durée de vie: si le but est de gérer un simple cache (pour optimiser le coût à l'exécution), quitte à devoir réinstancier un objet supprimé avant, on peut utiliser des "WeakReference" pour la collection d'instances stockées dans la classe Factory: getInstance s'occupe de regénérer une ancienne référence qui a été supprimée. Cette approche est souvent indispensable pour un déploiement sur un serveur où l'application va s'exécuter durant des périodes très longues et supporter des tas de composants et d'utilisateurs, les anciens objets ne devant pas encombrer la mémoire indéfiniment, alors que cela deviendra nettement plus couteux que de réinstancier plus tard seulement quand l'objet redeviendra utile.


Message édité par verdy_p le 01-02-2008 à 13:09:07
Reply

Marsh Posté le 01-02-2008 à 13:25:26    

Qu'est-ce qui te gène? Je réfute l'argument selon lequel un singleton doit absolument s'instancier lors du permier appel : un singleton peut aussi s'instancier avec sa classe, et c'est d'ailleurs ce qu'on doit commencer par faire d'abord avant de penser à une optimisation par instanciation différée ou "lazy" qui ne devrait avoir lieu qu'après profilage et tests mais pas lors du design initial et la création d'un squelette fonctionnel.
Et le défaut de gestion du cycle de vie (trop long) du singleton sur un serveur ou une application tournant très longtemp mais faisant une utilisation très rare de l'objet, se règle en utilisant comme membre de la classe singleton une WeakReference vers l'instance (la synchronisation reste nécessaire pour tester la WeakReference et réinstancier plus tard si nécessaire, tout en conservant la contrainte d'unicité), et non une référence statique simple.


Message édité par verdy_p le 01-02-2008 à 13:37:36
Reply

Marsh Posté le 01-02-2008 à 13:51:38    

UP UP \o/


---------------
I'm failing as fast as I can !! -- Vision-360, vos photos en grand format -- !! -- Les nouilles c'est bon
Reply

Marsh Posté le 01-02-2008 à 15:32:10    

_TT_ a écrit :


Non pas du tout, mais de liaison statique / dynamique à l'exécution.
 
Si tu as B hérite de A, et m1() est une méthode à la fois dans A et dans B (avec la même signature), si tu manipules un A dans un traitement (qui peut être indifférement un A ou un B), c'est la méthode m1() de l'objet réellement instancié qui est appelée et non pas la méthode de la classe déclarée manipulée :
 
traitement(A monObjet){  
    monObjet.m1()
}
 
Dans le cas d'une liaison dynamique :
Si tu passes un A, on appelera A.m1(), si tu passes un B, on appelera le m1() défini dans B. (cas d'un virtual m1() en C++ )
 
Dans le cas d'une liaison statique :
Que tu passes un A ou un B, on appelera toujours A.m1(). (cas d'un m1() en C++ )
 
Donc avec un singleton, c'est bien la liaison dynamique qui s'opère, vu qu'il est un objet instancié, et qu'en JAVA toutes les liaisons d'instances sont dynamiques.
[/#ff3800][/b]


Quelqu'un m'expliera l'utilité de la liaison dynamique sur un singleton qui par définition n'a qu'une seule instance disposant de toutes ses méthodes non surchargables (un singleton est aussi non clonable, ou son "clone" c'est lui-même). Si on a besoin d'étendre une classe singleton c'est pour lui ajouter des méthodes statiques uniquement qui auront éventuellement un accès à ses données internes sans devoir passer par ses accesseurs publics: cela ne change pas le nombre d'instance et c'est toujours le même objet qui sera manipulé par ces méthodes statiques supplémentaires, toute modification de l'état du singleton par ces méthodes statiques étant nécessairement reportées sur l'état de l'objet de base.
 
La vraie question est de savoir s'il vaut mieux avoir des méthodes statiques dans une classe ou des méthodes liée à l'instance unique instanciée par cette classe. Fonctionnellement cela ne change rien, mais cela change l'ordre de chargement et d'instanciation, le singletno permettant de différer le chargement de la classe jusqu'à ce que l'accesseur getInstance() soit appelé.
 
Si on prend Math par exemple, ses méthodes statiques sans accesseur sont plus pratiques, seulement car le singleton n'a pas d'état (hormi son membre qui contient une référence du générateur aléatoire dont l'instancuiation est différée). Le pattern singleton y est réduit à sa plus simple expression (même pas d'accesseur getInstance() dedans) en ne nécessitant pas une instance pour la quasi-totalité de ses méthodes puisque leur comportement ne dépend pas d'autres variables d'état que les seuls paramètres qu'on lui fournit temporairement et qui sont presque toujours de simples valeurs et même pas des objets à lier à ses variables d'état.
 
Contrairement à Javascript/ECMAscript par exemple, on ne peut pas changer les méthodes et attributs liés à une instance d'objet (que ce soit un singleton ou non). Le dynamisme est limité, la liste des méthodes et des attributs d'un objet n'est pas dynamique en Java, car c'est déterminé uniquement lors de l'instanciation initiale (c'est-à-dire l'appel de son constructeur).


Message édité par verdy_p le 01-02-2008 à 15:41:30
Reply

Marsh Posté le 01-02-2008 à 15:51:31    

_TT_ a écrit :


Mais j'ai toujours une seule instance de chaque classe. J'espère que c'est plus clair.


Pas clair du tout: comment tu peux nettoyer la table en surchargeant sa méthode nettoyer() dans un objet dérivé? Impossible. En revanche tu peux faire une table unique et une planche à roulette unique comme des singletons dérivés d'une classe qui n'est pas singleton mais fournit la méthode commune nettoyer(). Tu ne peut pas renverser cela en créant un objet dérivé de ta table et de ta planche à roulette: Java n'autorise pas de modifier les méthodes de ton singleton table ou de ton singleton planche à roulette une fois qu'ils sont instanciés opur leur donner un comportement commun après coup (tu peux le fait en Javascript...).
 
Moralité la seule utilité de dériver une classe de base singleton en Java est de lui ajouter un comportement statique. En "design by patterns" strict, un singleton n'est pas dérivable (et devrait même être déclaré "final", sauf si on compte ajouter des méthodes statiques qui ne créront pas de nouvelles instances), et il n'est pas possible non plus de cnotrôler la durée de vie de l'instance unique pour espérer détruire l'objet et le remplacer par une autre instance construite dans un autre objet (sachant aussi que l'héritage multiple sur autre chose que des interfaces n'existe pas en Java).
 
Ceci dit je suis d'accord avec toi: "static" ne signifie pas "thread-safe" (c'est même plutôt exactement le contraire: c'est justement là qu'on a besoin très souvent de synchronisation, et que la question de la pertinence d'un singleton doit être posée à cause des conséquences sur la performance liée à la synchronisation dans une appli multi-thread). Un singleton (ou un membre statique) en Java c'est comme une variable globale en BASIC: peu d'effort mais beaucoup de contraintes... Et la dificulté de débogage et de prédiction du comportement milite en faveur des langages fonctionnels (où il n'y a aucun singleton ni aucune variable statique, tout devant passer par des références explicites aux objets manipulés dans les paramètres des méthodes).

Message cité 1 fois
Message édité par verdy_p le 01-02-2008 à 16:01:25
Reply

Marsh Posté le 01-02-2008 à 17:46:04    

Dernier message posté avant moi il y a 10 jours, c'est pas ce que j'appelle mort sur le forum Java... ils sont seulement absents, ou occupés ailleurs pour l'instant.

Reply

Marsh Posté le 05-02-2008 à 00:00:48    

Oui, d'autant que le post de verdy n'est pas vraiment un post juste pour faire remonter le topic : il y a mis de la substance... dont même ceux qui n'étaient jamais venu sur le topic pourront profiter.

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed