Ich habe unten einige Antworten gesehen, die verschiedene Möglichkeiten beschreiben, einen Klassen-Singleton zu erstellen. Ich denke also darüber nach, warum uns dieses class_name-Objekt nicht gefällt. if (object == null) return object = neuer Klassenname; sonst Objekt zurückgeben
Avnish Kumar
Antworten:
320
Dank der Fabrikkonstrukteure von Dart ist es einfach, einen Singleton zu bauen:
Obwohl, was ist der Sinn, es zweimal zu instanziieren? Sollte es nicht besser sein, wenn beim zweiten Instanziieren ein Fehler aufgetreten ist?
Westoque
53
Ich instanziiere es nicht zweimal, sondern erhalte nur zweimal einen Verweis auf ein Singleton-Objekt. Sie würden es im wirklichen Leben wahrscheinlich nicht zweimal hintereinander tun :) Ich möchte nicht, dass eine Ausnahme ausgelöst wird. Ich möchte nur jedes Mal dieselbe Singleton-Instanz, wenn ich "new Singleton ()" sage. Ich gebe zu, es ist ein bisschen verwirrend ... newbedeutet hier nicht "einen neuen konstruieren", sondern nur "den Konstruktor ausführen".
Seth Ladd
1
Was genau dient das Factory-Schlüsselwort hier? Es handelt sich lediglich um eine Annotation der Implementierung. Warum ist es erforderlich?
Καrτhικ
4
Es ist etwas verwirrend, dass Sie einen Konstruktor verwenden, um die Instanz abzurufen. Das newSchlüsselwort legt nahe, dass die Klasse instanziiert ist, was nicht der Fall ist. Ich würde mich für eine statische Methode entscheiden get()oder getInstance()wie in Java.
Steven Roose
11
@ SethLadd das ist sehr schön, aber ich schlage vor, es braucht ein paar Erklärungen. Es gibt die seltsame Syntax Singleton._internal();, die wie ein Methodenaufruf aussieht, wenn es sich wirklich um eine Konstruktordefinition handelt. Da ist der _internalName. Und es gibt den raffinierten Sprachentwurfspunkt, mit dem Sie mit Dart mit einem normalen Konstruktor beginnen (Dart out?) Und ihn dann bei Bedarf in eine factoryMethode ändern können, ohne alle Aufrufer zu ändern.
Jerry101
169
Hier finden Sie einen Vergleich verschiedener Möglichkeiten zum Erstellen eines Singletons in Dart.
Die obigen Singletons werden folgendermaßen instanziiert:
SingletonOne one =SingletonOne();SingletonTwo two =SingletonTwo.instance;SingletonThree three =SingletonThree.instance;
Hinweis:
Ich habe dies ursprünglich als Frage gestellt , aber festgestellt, dass alle oben genannten Methoden gültig sind und die Auswahl weitgehend von den persönlichen Vorlieben abhängt.
Ich habe gerade Ihre Antwort positiv bewertet. Viel klarer als die akzeptierte Antwort. Nur noch eine Frage: Was ist der Sinn eines privaten Konstrukteurs für den zweiten und dritten Weg? Ich habe gesehen, dass viele Leute das getan haben, aber ich verstehe den Punkt nicht. Ich benutze immer einfach static final SingletonThree instance = SingletonThree(). Gleiches gilt für den zweiten Weg _instance. Ich weiß nicht, was der Nachteil ist, keinen privaten Konstruktor zu verwenden. Bisher finde ich keine Probleme im Weg. Die zweite und dritte Möglichkeit blockieren den Aufruf des Standardkonstruktors ohnehin nicht.
sgon00
3
@ sgon00, der private Konstruktor ist so, dass Sie keine weitere Instanz erstellen können. Sonst könnte jeder machen SingletonThree instance2 = SingletonThree(). Wenn Sie versuchen, dies zu tun, wenn es einen privaten Konstruktor gibt, erhalten Sie die Fehlermeldung:The class 'SingletonThree' doesn't have a default constructor.
Suragch
40
Ich finde es nicht sehr intuitiv zu lesen new Singleton(). Sie müssen die Dokumente lesen, um das zu wissennew keine neue Instanz erstellt wird, wie dies normalerweise der Fall ist.
Hier ist eine andere Möglichkeit, Singletons zu machen (im Grunde das, was Andrew oben gesagt hat).
Beachten Sie, dass der Singleton erst erstellt wird, wenn der Getter aufgrund der verzögerten Initialisierung von Dart zum ersten Mal aufgerufen wird.
Wenn Sie möchten, können Sie Singletons auch als statischen Getter für die Singleton-Klasse implementieren. dhThing.singleton anstelle eines Top-Level-Getters.
Dies ist für mich dank Greg und der Eigenschaft der Top-Level-Eigenschaft von Dart sinnvoller.
Eason PI
Das ist keine Redewendung. Es ist eine Traumfunktion, ein Singleton-Muster in der Sprache zu erstellen, und Sie werfen es weg, weil Sie nicht daran gewöhnt sind.
Arash
1
Sowohl Seths Beispiel als auch dieses Beispiel sind Singleton-Muster. Es ist wirklich eine Frage der Syntax "new Singleton ()" vs "singleton". Letzteres finde ich klarer. Darts Fabrikkonstrukteure sind nützlich, aber ich denke nicht, dass dies ein guter Anwendungsfall für sie ist. Ich denke auch, dass Darts faule Initialisierung eine großartige Funktion ist, die nicht ausreichend genutzt wird. Lesen Sie auch Bobs Artikel oben - er empfiehlt in den meisten Fällen gegen Singletons.
Das ist viel besser. Das Schlüsselwort "new" impliziert ziemlich stark die Konstruktion eines neuen Objekts. Die akzeptierte Lösung fühlt sich wirklich falsch an.
Sava B.
16
Wie wäre es, wenn Sie einfach eine globale Variable in Ihrer Bibliothek verwenden?
import'single.dart';void main(){var a =Singleton;var b =Singleton;
a.i =2;
print(b.i);}
Oder ist das verpönt?
Das Singleton-Muster ist in Java erforderlich, wo das Konzept der Globalen nicht existiert, aber es scheint, dass Sie in Dart nicht den weiten Weg gehen müssen.
Variablen der obersten Ebene sind cool. Jeder, der single.dart importieren kann, kann jedoch ein "neues Impl ()" erstellen. Sie könnten Impl einen Unterstrichkonstruktor geben, aber dann könnte Code in der Singleton-Bibliothek diesen Konstruktor aufrufen.
Seth Ladd
Und der Code in Ihrer Implementierung kann nicht? Können Sie in Ihrer Antwort erklären, warum es besser ist als eine Variable der obersten Ebene?
Januar
2
Hallo @Jan, es ist nicht besser oder schlechter, es ist einfach anders. In Andrews Beispiel ist Impl keine Singleton-Klasse. Er hat eine Variable der obersten Ebene korrekt verwendet, um den SingletonZugriff auf die Instanz zu vereinfachen. In meinem obigen Beispiel ist die SingletonKlasse ein echter Singleton, von dem nur eine Instanz Singletonim Isolat existieren kann.
Seth Ladd
1
Seth, du hast nicht recht. In Dart gibt es keine Möglichkeit, einen echten Singleton zu erstellen, da es keine Möglichkeit gibt, die Instantiierbarkeit einer Klasse in der deklarierenden Bibliothek einzuschränken . Es erfordert immer Disziplin vom Bibliotheksautor. In Ihrem Beispiel kann die deklarierende Bibliothek new Singleton._internal()so oft aufrufen, wie sie möchte, und so viele Objekte der SingletonKlasse erstellen . Wenn die ImplKlasse in Andrews Beispiel privat ( _Impl) wäre, wäre sie dieselbe wie Ihr Beispiel. Auf der anderen Seite ist Singleton ein Antimuster und niemand sollte es trotzdem benutzen.
Ladicek
@Ladicek, vertrauen Sie nicht dem Entwickler einer Bibliothek nicht neu zu nennen Singelton._internal(). Sie können argumentieren, dass die Entwickler der Singelton-Klasse die Klasse auch mehrmals initiieren könnten. Sicher gibt es das Enum Singelton, aber für mich ist es nur von theoretischem Nutzen. Eine Aufzählung ist eine Aufzählung, kein Singelton ... Was die Verwendung von Variablen der obersten Ebene (@Andrew und @Seth) betrifft: Könnte niemand in die Variable der obersten Ebene schreiben? Es ist keineswegs geschützt, oder fehlt mir etwas?
Tobias Ritzau
12
Hier ist ein anderer möglicher Weg:
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;}
Hallo was ist mit so etwas? Sehr einfache Implementierung, Injector selbst ist Singleton und hat auch Klassen hinzugefügt. Natürlich kann sehr einfach erweitert werden. Wenn Sie nach etwas Anspruchsvollerem suchen, überprüfen Sie dieses Paket: https://pub.dartlang.org/packages/flutter_simple_dependency_injection
Bitte posten Sie keine Folgefragen als Antworten. Das Problem mit diesem Code ist, dass er etwas ausführlich ist. static GlobalStore get instance => _instance ??= new GlobalStore._();würdest du. Was _(){}soll tun? Dies scheint überflüssig.
Günter Zöchbauer
Entschuldigung, das war ein Vorschlag, keine Folgefrage. _ () {} wird einen privaten Konstruktor erstellen, oder?
Vilsad PP
Konstruktoren beginnen mit dem Klassennamen. Dies ist nur eine normale private Instanzmethode ohne Angabe eines Rückgabetyps.
Günter Zöchbauer
1
Entschuldigen Sie die Ablehnung, aber ich denke, es ist von schlechter Qualität und bietet keinen Mehrwert zusätzlich zu den vorhandenen Antworten.
Günter Zöchbauer
2
Während dieser Code die Frage möglicherweise beantwortet, würde die Bereitstellung eines zusätzlichen Kontexts darüber, wie und / oder warum das Problem gelöst wird, den langfristigen Wert der Antwort verbessern.
Karl Richter
0
Da ich das newSchlüsselwort oder einen anderen Konstruktor wie Aufrufe von Singletons nicht sehr gern verwende , würde ich lieber einen statischen Getter verwenden, der instzum Beispiel aufgerufen wird :
// the singleton classclassDao{// singleton boilerplateDao._internal(){}staticfinalDao _singleton =newDao._internal();staticget inst => _singleton;// business logicvoid greet()=> print("Hello from singleton");}
Anwendungsbeispiel:
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));
Antworten:
Dank der Fabrikkonstrukteure von Dart ist es einfach, einen Singleton zu bauen:
Sie können es so konstruieren
quelle
new
bedeutet hier nicht "einen neuen konstruieren", sondern nur "den Konstruktor ausführen".new
Schlüsselwort legt nahe, dass die Klasse instanziiert ist, was nicht der Fall ist. Ich würde mich für eine statische Methode entscheidenget()
odergetInstance()
wie in Java.Singleton._internal();
, die wie ein Methodenaufruf aussieht, wenn es sich wirklich um eine Konstruktordefinition handelt. Da ist der_internal
Name. Und es gibt den raffinierten Sprachentwurfspunkt, mit dem Sie mit Dart mit einem normalen Konstruktor beginnen (Dart out?) Und ihn dann bei Bedarf in einefactory
Methode ändern können, ohne alle Aufrufer zu ändern.Hier finden Sie einen Vergleich verschiedener Möglichkeiten zum Erstellen eines Singletons in Dart.
1. Fabrikkonstrukteur
2. Statisches Feld mit Getter
3. Statisches Feld
Wie man instanstiiert
Die obigen Singletons werden folgendermaßen instanziiert:
Hinweis:
Ich habe dies ursprünglich als Frage gestellt , aber festgestellt, dass alle oben genannten Methoden gültig sind und die Auswahl weitgehend von den persönlichen Vorlieben abhängt.
quelle
static final SingletonThree instance = SingletonThree()
. Gleiches gilt für den zweiten Weg_instance
. Ich weiß nicht, was der Nachteil ist, keinen privaten Konstruktor zu verwenden. Bisher finde ich keine Probleme im Weg. Die zweite und dritte Möglichkeit blockieren den Aufruf des Standardkonstruktors ohnehin nicht.SingletonThree instance2 = SingletonThree()
. Wenn Sie versuchen, dies zu tun, wenn es einen privaten Konstruktor gibt, erhalten Sie die Fehlermeldung:The class 'SingletonThree' doesn't have a default constructor.
Ich finde es nicht sehr intuitiv zu lesen
new Singleton()
. Sie müssen die Dokumente lesen, um das zu wissennew
keine neue Instanz erstellt wird, wie dies normalerweise der Fall ist.Hier ist eine andere Möglichkeit, Singletons zu machen (im Grunde das, was Andrew oben gesagt hat).
lib / thing.dart
main.dart
Beachten Sie, dass der Singleton erst erstellt wird, wenn der Getter aufgrund der verzögerten Initialisierung von Dart zum ersten Mal aufgerufen wird.
Wenn Sie möchten, können Sie Singletons auch als statischen Getter für die Singleton-Klasse implementieren. dh
Thing.singleton
anstelle eines Top-Level-Getters.Lesen Sie auch Bob Nystroms Version von Singletons aus seinem Spielprogrammiermusterbuch .
quelle
Wie wäre es, wenn Sie einfach eine globale Variable in Ihrer Bibliothek verwenden?
single.dart
::main.dart
::Oder ist das verpönt?
Das Singleton-Muster ist in Java erforderlich, wo das Konzept der Globalen nicht existiert, aber es scheint, dass Sie in Dart nicht den weiten Weg gehen müssen.
quelle
Singleton
Zugriff auf die Instanz zu vereinfachen. In meinem obigen Beispiel ist dieSingleton
Klasse ein echter Singleton, von dem nur eine InstanzSingleton
im Isolat existieren kann.new Singleton._internal()
so oft aufrufen, wie sie möchte, und so viele Objekte derSingleton
Klasse erstellen . Wenn dieImpl
Klasse in Andrews Beispiel privat (_Impl
) wäre, wäre sie dieselbe wie Ihr Beispiel. Auf der anderen Seite ist Singleton ein Antimuster und niemand sollte es trotzdem benutzen.Singelton._internal()
. Sie können argumentieren, dass die Entwickler der Singelton-Klasse die Klasse auch mehrmals initiieren könnten. Sicher gibt es das Enum Singelton, aber für mich ist es nur von theoretischem Nutzen. Eine Aufzählung ist eine Aufzählung, kein Singelton ... Was die Verwendung von Variablen der obersten Ebene (@Andrew und @Seth) betrifft: Könnte niemand in die Variable der obersten Ebene schreiben? Es ist keineswegs geschützt, oder fehlt mir etwas?Hier ist ein anderer möglicher Weg:
quelle
Dart Singleton von Const Konstruktor & Fabrik
quelle
Singleton, der das Objekt nach der Instanz nicht ändern kann
quelle
Modifizierte @ Seth Ladd-Antwort für diejenigen, die den Swift-Singleton-Stil bevorzugen, wie
.shared
:Stichprobe:
quelle
Nachdem ich alle Alternativen gelesen hatte, kam ich auf diese Idee, die mich an einen "klassischen Singleton" erinnert:
quelle
getInstance
Methode in einerinstance
Eigenschaft wie dieser ändern :static AccountService get instance => _instance;
Hier ist eine einfache Antwort:
quelle
Hier ist ein kurzes Beispiel, das die anderen Lösungen kombiniert. Der Zugriff auf den Singleton kann erfolgen über:
singleton
globalen Variablen, die auf die Instanz verweist.Singleton.instance
Muster.Hinweis: Sie sollten nur eine der drei Optionen implementieren, damit der Code mit dem Singleton konsistent ist.
Wenn Sie eine komplexe Initialisierung durchführen müssen, müssen Sie dies nur tun, bevor Sie die Instanz später im Programm verwenden.
Beispiel
quelle
Hallo was ist mit so etwas? Sehr einfache Implementierung, Injector selbst ist Singleton und hat auch Klassen hinzugefügt. Natürlich kann sehr einfach erweitert werden. Wenn Sie nach etwas Anspruchsvollerem suchen, überprüfen Sie dieses Paket: https://pub.dartlang.org/packages/flutter_simple_dependency_injection
quelle
Das sollte funktionieren.
quelle
static GlobalStore get instance => _instance ??= new GlobalStore._();
würdest du. Was_(){}
soll tun? Dies scheint überflüssig.Da ich das
new
Schlüsselwort oder einen anderen Konstruktor wie Aufrufe von Singletons nicht sehr gern verwende , würde ich lieber einen statischen Getter verwenden, derinst
zum Beispiel aufgerufen wird :Anwendungsbeispiel:
quelle