J'ai vu plusieurs réponses ci-dessous qui décrivent plusieurs façons de créer un singleton de classe. Je réfléchis donc à la raison pour laquelle nous n'aimons pas cet objet class_name; if (object == null) return object = new nom_classe; else return object
Mais quel est l'intérêt de l'instancier deux fois? Ne devrait-il pas être préférable qu'il génère une erreur lorsque vous l'instanciez la deuxième fois?
westoque
54
Je ne l'instancie pas deux fois, je reçois simplement une référence à un objet Singleton deux fois. Vous ne le feriez probablement pas deux fois de suite dans la vraie vie :) Je ne voudrais pas qu'une exception soit levée, je veux juste la même instance de singleton à chaque fois que je dis "new Singleton ()". J'admets que c'est un peu déroutant ... newça ne veut pas dire "en construire un nouveau" ici, ça dit juste "exécuter le constructeur".
Seth Ladd
1
À quoi sert exactement le mot-clé d'usine ici? Il s'agit purement d'annoter la mise en œuvre. Pourquoi est-ce nécessaire?
Καrτhικ
4
Il est un peu déroutant d'utiliser un constructeur pour obtenir l'instance. Le newmot clé suggère que la classe est instanciée, ce qui n'est pas le cas. J'irais pour une méthode statique get()ou getInstance()comme je le fais en Java.
Steven Roose
11
@SethLadd c'est très bien mais je suggère que cela nécessite quelques points d'explication. Il y a la syntaxe étrange Singleton._internal();qui ressemble à un appel de méthode alors qu'il s'agit vraiment d'une définition de constructeur. Voilà le _internalnom. Et il y a le point de conception du langage astucieux que Dart vous permet de commencer (darder?) En utilisant un constructeur ordinaire, puis, si nécessaire, de le changer en factoryméthode sans changer tous les appelants.
Jerry101
174
Voici une comparaison de plusieurs façons différentes de créer un singleton dans Dart.
Les singletons ci-dessus sont instanciés comme ceci:
SingletonOne one =SingletonOne();SingletonTwo two =SingletonTwo.instance;SingletonThree three =SingletonThree.instance;
Remarque:
J'ai initialement posé cette question , mais j'ai découvert que toutes les méthodes ci-dessus sont valides et que le choix dépend en grande partie de vos préférences personnelles.
Je viens de voter pour votre réponse. Beaucoup plus clair que la réponse acceptée. Encore une question: pour la deuxième et la troisième manière, quel est l'intérêt du constructeur privé? J'ai vu beaucoup de gens faire ça, mais je ne comprends pas le point. J'utilise toujours simplement static final SingletonThree instance = SingletonThree(). Il en va de même pour la deuxième méthode _instance. Je ne sais pas quel est l'inconvénient de ne pas utiliser de constructeur privé. Jusqu'à présent, je ne trouve aucun problème sur mon chemin. De toute façon, les deuxième et troisième moyens ne bloquent pas l'appel au constructeur par défaut.
sgon00
3
@ sgon00, le constructeur privé est pour que vous ne puissiez pas créer une autre instance. Sinon, n'importe qui pourrait le faire SingletonThree instance2 = SingletonThree(). Si vous essayez de faire cela quand il y a un constructeur privé, vous obtiendrez l'erreur:The class 'SingletonThree' doesn't have a default constructor.
Suragch
41
Je ne trouve pas la lecture très intuitive new Singleton(). Vous devez lire la documentation pour savoir que cela newne crée pas réellement une nouvelle instance, comme cela le ferait normalement.
Voici une autre façon de faire des singletons (en gros ce qu'Andrew a dit ci-dessus).
Notez que le singleton n'est créé que lors du premier appel du getter en raison de l'initialisation paresseuse de Dart.
Si vous préférez, vous pouvez également implémenter des singletons comme getter statique sur la classe singleton. c'est-à Thing.singleton- dire au lieu d'un getter de premier niveau.
Cela a plus de sens pour moi, grâce à Greg et à la fonctionnalité de propriété de premier niveau de dart.
Eason PI du
Ce n'est pas idiomatique. C'est une fonctionnalité de rêve d'avoir un modèle unique dans le langage, et vous le jetez parce que vous n'y êtes pas habitué.
Arash
1
L'exemple de Seth et cet exemple sont des modèles singleton. C'est vraiment une question de syntaxe "new Singleton ()" vs "singleton". Je trouve ce dernier plus clair. Les constructeurs d'usine de Dart sont utiles, mais je ne pense pas que ce soit un bon cas d'utilisation pour eux. Je pense également que l'initialisation paresseuse de Dart est une fonctionnalité intéressante, qui est sous-utilisée. Lisez également l'article de Bob ci-dessus - il recommande d'éviter les singletons dans la plupart des cas.
import'single.dart';void main(){var a =Singleton;var b =Singleton;
a.i =2;
print(b.i);}
Ou est-ce mal vu?
Le modèle singleton est nécessaire en Java où le concept de globals n'existe pas, mais il semble que vous ne devriez pas avoir besoin de parcourir le long chemin dans Dart.
Les variables de premier niveau sont cool. Cependant, quiconque peut importer single.dart est libre de construire un "new Impl ()". Vous pouvez donner un constructeur de soulignement à Impl, mais le code à l' intérieur de la bibliothèque singleton peut appeler ce constructeur.
Seth Ladd
Et le code de votre implémentation ne peut pas? Pouvez-vous expliquer dans votre réponse pourquoi c'est mieux qu'une variable de premier niveau?
janvier
2
Salut @Jan, ce n'est ni meilleur ni pire, c'est juste différent. Dans l'exemple d'Andrew, Impl n'est pas une classe singleton. Il a correctement utilisé une variable de niveau supérieur pour rendre l'instance Singletonfacile d'accès. Dans mon exemple ci-dessus, la Singletonclasse est un vrai singleton, une seule instance de Singletonpeut exister dans l'isolat.
Seth Ladd
1
Seth, tu n'as pas raison. Il n'y a aucun moyen dans Dart de construire un vrai singleton, car il n'y a aucun moyen de restreindre l'instancabilité d'une classe à l' intérieur de la bibliothèque de déclaration. Cela exige toujours de la discipline de la part de l'auteur de la bibliothèque. Dans votre exemple, la bibliothèque déclarante peut appeler new Singleton._internal()autant de fois qu'elle le souhaite, créant de nombreux objets de la Singletonclasse. Si la Implclasse de l'exemple d'Andrew était private ( _Impl), ce serait la même chose que votre exemple. D'un autre côté, singleton est un anti-modèle et personne ne devrait l'utiliser de toute façon.
Ladicek
@Ladicek, ne faites pas confiance aux développeurs d'une bibliothèque pour ne pas en appeler de nouveau Singelton._internal(). Vous pouvez affirmer que les développeurs de la classe singelton pourraient également installer la classe plusieurs fois. Bien sûr, il y a l'énum singelton, mais pour moi, ce n'est que théorique. Une énumération est une énumération, pas un singelton ... Quant à l'utilisation des variables de niveau supérieur (@Andrew et @Seth): Personne ne pourrait écrire dans la variable de niveau supérieur? Il n'est en aucun cas protégé ou est-ce que je manque quelque chose?
Tobias Ritzau
12
Voici un autre moyen possible:
void main(){var s1 =Singleton.instance;
s1.somedata =123;var s2 =Singleton.instance;
print(s2.somedata);// 123
print(identical(s1, s2));// true
print(s1 == s2);// true//var s3 = new Singleton(); //produces a warning re missing default constructor and breaks on execution}classSingleton{staticfinalSingleton _singleton =newSingleton._internal();Singleton._internal();staticSingletonget instance => _singleton;var somedata;}
Bonjour et quelque chose comme ça? Implémentation très simple, Injector lui-même est singleton et y a également ajouté des classes. Bien sûr, peut être étendu très facilement. Si vous cherchez quelque chose de plus sophistiqué, vérifiez ce package: https://pub.dartlang.org/packages/flutter_simple_dependency_injection
Veuillez ne pas publier de questions de suivi comme réponses. Le problème avec ce code est qu'il est un peu détaillé. static GlobalStore get instance => _instance ??= new GlobalStore._();ferait. Que _(){}doit-on faire? Cela semble redondant.
Günter Zöchbauer
désolé, c'était une suggestion, pas une question de suivi, _ () {} créera un constructeur privé, non?
Vilsad PP
Les constructeurs commencent par le nom de la classe. Il s'agit simplement d'une méthode d'instance privée normale sans type de retour spécifié.
Günter Zöchbauer
1
Désolé pour le vote négatif, mais je pense qu'il est de mauvaise qualité et n'ajoute aucune valeur en plus des réponses existantes.
Günter Zöchbauer
2
Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire sur la manière et / ou la raison pour laquelle il résout le problème améliorerait la valeur à long terme de la réponse.
Karl Richter
0
Comme je n'aime pas beaucoup utiliser le newmot - clé ou un autre constructeur comme les appels sur des singletons, je préférerais utiliser un getter statique appelé instpar exemple:
// the singleton classclassDao{// singleton boilerplateDao._internal(){}staticfinalDao _singleton =newDao._internal();staticget inst => _singleton;// business logicvoid greet()=> print("Hello from singleton");}
exemple d'utilisation:
Dao.inst.greet();// call a method// Dao x = new Dao(); // compiler error: Method not found: 'Dao'// verify that there only exists one and only one instanceassert(identical(Dao.inst,Dao.inst));
Réponses:
Grâce aux constructeurs d'usine de Dart , il est facile de créer un singleton:
Vous pouvez le construire comme ça
la source
new
ça ne veut pas dire "en construire un nouveau" ici, ça dit juste "exécuter le constructeur".new
mot clé suggère que la classe est instanciée, ce qui n'est pas le cas. J'irais pour une méthode statiqueget()
ougetInstance()
comme je le fais en Java.Singleton._internal();
qui ressemble à un appel de méthode alors qu'il s'agit vraiment d'une définition de constructeur. Voilà le_internal
nom. Et il y a le point de conception du langage astucieux que Dart vous permet de commencer (darder?) En utilisant un constructeur ordinaire, puis, si nécessaire, de le changer enfactory
méthode sans changer tous les appelants.Voici une comparaison de plusieurs façons différentes de créer un singleton dans Dart.
1. Constructeur d'usine
2. Champ statique avec getter
3. Champ statique
Comment instanster
Les singletons ci-dessus sont instanciés comme ceci:
Remarque:
J'ai initialement posé cette question , mais j'ai découvert que toutes les méthodes ci-dessus sont valides et que le choix dépend en grande partie de vos préférences personnelles.
la source
static final SingletonThree instance = SingletonThree()
. Il en va de même pour la deuxième méthode_instance
. Je ne sais pas quel est l'inconvénient de ne pas utiliser de constructeur privé. Jusqu'à présent, je ne trouve aucun problème sur mon chemin. De toute façon, les deuxième et troisième moyens ne bloquent pas l'appel au constructeur par défaut.SingletonThree instance2 = SingletonThree()
. Si vous essayez de faire cela quand il y a un constructeur privé, vous obtiendrez l'erreur:The class 'SingletonThree' doesn't have a default constructor.
Je ne trouve pas la lecture très intuitive
new Singleton()
. Vous devez lire la documentation pour savoir que celanew
ne crée pas réellement une nouvelle instance, comme cela le ferait normalement.Voici une autre façon de faire des singletons (en gros ce qu'Andrew a dit ci-dessus).
lib / chose.dart
main.dart
Notez que le singleton n'est créé que lors du premier appel du getter en raison de l'initialisation paresseuse de Dart.
Si vous préférez, vous pouvez également implémenter des singletons comme getter statique sur la classe singleton. c'est-à
Thing.singleton
- dire au lieu d'un getter de premier niveau.Lisez également le point de vue de Bob Nystrom sur les singletons dans son livre de modèles de programmation de jeu .
la source
Qu'en est-il simplement d'utiliser une variable globale dans votre bibliothèque, comme ça?
single.dart
:main.dart
:Ou est-ce mal vu?
Le modèle singleton est nécessaire en Java où le concept de globals n'existe pas, mais il semble que vous ne devriez pas avoir besoin de parcourir le long chemin dans Dart.
la source
Singleton
facile d'accès. Dans mon exemple ci-dessus, laSingleton
classe est un vrai singleton, une seule instance deSingleton
peut exister dans l'isolat.new Singleton._internal()
autant de fois qu'elle le souhaite, créant de nombreux objets de laSingleton
classe. Si laImpl
classe de l'exemple d'Andrew était private (_Impl
), ce serait la même chose que votre exemple. D'un autre côté, singleton est un anti-modèle et personne ne devrait l'utiliser de toute façon.Singelton._internal()
. Vous pouvez affirmer que les développeurs de la classe singelton pourraient également installer la classe plusieurs fois. Bien sûr, il y a l'énum singelton, mais pour moi, ce n'est que théorique. Une énumération est une énumération, pas un singelton ... Quant à l'utilisation des variables de niveau supérieur (@Andrew et @Seth): Personne ne pourrait écrire dans la variable de niveau supérieur? Il n'est en aucun cas protégé ou est-ce que je manque quelque chose?Voici un autre moyen possible:
la source
Dart singleton par constructeur et usine const
la source
Singleton qui ne peut pas changer l'objet après l'instance
la source
Réponse modifiée de @Seth Ladd pour qui préfère le style de singleton Swift comme
.shared
:Échantillon:
la source
Après avoir lu toutes les alternatives, je suis venu avec ceci, qui me rappelle un "singleton classique":
la source
getInstance
méthode dans uneinstance
propriété comme celle-ci:static AccountService get instance => _instance;
Voici une réponse simple:
la source
Voici un exemple concis qui combine les autres solutions. L'accès au singleton peut se faire par:
singleton
variable globale qui pointe vers l'instance.Singleton.instance
modèle commun .Remarque: vous ne devez implémenter qu'une des trois options afin que le code utilisant le singleton soit cohérent.
Si vous devez effectuer une initialisation complexe, vous devrez simplement le faire avant d'utiliser l'instance ultérieurement dans le programme.
Exemple
la source
Bonjour et quelque chose comme ça? Implémentation très simple, Injector lui-même est singleton et y a également ajouté des classes. Bien sûr, peut être étendu très facilement. Si vous cherchez quelque chose de plus sophistiqué, vérifiez ce package: https://pub.dartlang.org/packages/flutter_simple_dependency_injection
la source
Cela devrait fonctionner.
la source
static GlobalStore get instance => _instance ??= new GlobalStore._();
ferait. Que_(){}
doit-on faire? Cela semble redondant.Comme je n'aime pas beaucoup utiliser le
new
mot - clé ou un autre constructeur comme les appels sur des singletons, je préférerais utiliser un getter statique appeléinst
par exemple:exemple d'utilisation:
la source