Widziałem kilka odpowiedzi poniżej, które opisują kilka sposobów na utworzenie singletonu klasowego. Zastanawiam się więc, dlaczego nie lubimy tego obiektu nazwa_klasy; if (object == null) return object = nowa nazwa_klasy; w przeciwnym razie zwróci obiekt
Chociaż po co dwa razy tworzyć instancję? Czy nie powinno być lepiej, jeśli po raz drugi wystąpił błąd?
westokalny
53
Nie tworzę go dwa razy, tylko dwa razy otrzymuję odniesienie do obiektu Singleton. Prawdopodobnie nie zrobiłbyś tego dwa razy z rzędu w prawdziwym życiu :) Nie chciałbym zgłaszać wyjątku, chcę tylko tę samą instancję singletonu za każdym razem, gdy mówię „new Singleton ()”. Przyznaję, jest to trochę mylące ... newnie oznacza tutaj „skonstruowania nowego”, a jedynie „uruchom konstruktora”.
Seth Ladd
1
Co dokładnie służy tutaj słowo kluczowe fabryka? Jest to wyłącznie adnotacja o implementacji. Dlaczego jest to wymagane?
Καrτhικ
4
To trochę mylące, że używasz konstruktora, aby uzyskać instancję. newKluczowe sugeruje, że klasa jest instancja, która nie jest. Wybrałbym metodę statyczną get()lub getInstance()jak ja w Javie.
Steven Roose
11
@SethLadd jest to bardzo miłe, ale sugeruję, że potrzebuje kilku wyjaśnień. Istnieje dziwna składnia, Singleton._internal();która wygląda jak wywołanie metody, gdy jest to naprawdę definicja konstruktora. Tam jest _internalnazwa. Jest też sprytny projektowy język, w którym Dart pozwala rozpocząć (rzutem?) Za pomocą zwykłego konstruktora, a następnie, w razie potrzeby, zmienić go na factorymetodę bez zmiany wszystkich wywołujących.
Jerry101
170
Oto porównanie kilku różnych sposobów na utworzenie singletona w Dart.
Właśnie głosowałem twoją odpowiedź. Znacznie wyraźniej niż zaakceptowana odpowiedź. Jeszcze tylko jedno pytanie: po co drugi i trzeci sposób, jaki jest sens prywatnego konstruktora? Widziałem, jak wiele osób to robiło, ale nie rozumiem o co chodzi. Zawsze po prostu używam static final SingletonThree instance = SingletonThree(). To samo dotyczy drugiego sposobu _instance. Nie wiem, co jest wadą nieużywania prywatnego konstruktora. Jak dotąd nie mam żadnych problemów. Drugi i trzeci sposób i tak nie blokują wywołania domyślnego konstruktora.
sgon00
3
@ sgon00, prywatny konstruktor jest tak, że nie można utworzyć innej instancji. W przeciwnym razie każdy mógłby to zrobić SingletonThree instance2 = SingletonThree(). Jeśli spróbujesz to zrobić, gdy istnieje prywatny konstruktor, pojawi się błąd:The class 'SingletonThree' doesn't have a default constructor.
Suragch
40
Nie uważam tego za bardzo intuicyjne czytanie new Singleton(). Musisz przeczytać dokumenty, aby wiedzieć, że newtak naprawdę nie tworzy nowej instancji, jak zwykle.
Oto inny sposób na tworzenie singletonów (w zasadzie to, co Andrew powiedział powyżej).
Zauważ, że singleton nie zostanie utworzony do pierwszego wywołania gettera z powodu leniwej inicjalizacji Dart.
Jeśli wolisz, możesz także zaimplementować singletony jako statyczny getter w klasie singletonów. tj. Thing.singletonzamiast getter najwyższego poziomu.
Ma to dla mnie więcej sensu, dzięki Gregowi i funkcji najwyższego poziomu właściwości rzutki.
Eason PI
To nie jest idiomatyczne. To marzenie, aby mieć wzorzec singletonu w języku, a ty go wyrzucasz, ponieważ nie jesteś do tego przyzwyczajony.
Arash
1
Zarówno przykład Setha, jak i ten przykład są wzorcami singletonowymi. To naprawdę kwestia składni „new Singleton ()” vs „singleton”. Uważam to drugie za bardziej jasne. Konstruktorzy fabryki Dart są przydatni, ale nie sądzę, że jest to dla nich dobry przypadek użycia. Myślę również, że leniwa inicjalizacja Dart jest świetną funkcją, która jest niewykorzystana. Przeczytaj także powyższy artykuł Boba - w większości przypadków odradza on singletony.
Zmienne najwyższego poziomu są fajne. Jednak każdy, kto może zaimportować single.dart, może utworzyć „nową Impl ()”. Możesz podać konstruktorowi podkreślenia do Impl, ale następnie kod w bibliotece singletona może wywołać tego konstruktora.
Seth Ladd,
A kod w twojej implementacji nie może? Czy potrafisz wyjaśnić w swojej odpowiedzi, dlaczego jest lepsza niż zmienna najwyższego poziomu?
stycznia
2
Cześć, Jan, nie jest ani lepsze ani gorsze, po prostu jest inne. W przykładzie Andrew Impl nie jest lekcją singleton. Prawidłowo użył zmiennej najwyższego poziomu, aby ułatwić dostęp do instancji Singleton. W moim przykładzie powyżej Singletonklasa jest prawdziwym singletonem, tylko jedna instancja Singletonmoże kiedykolwiek istnieć w izolatce.
Seth Ladd,
1
Seth, nie masz racji. W Dart nie ma sposobu na zbudowanie prawdziwego singletona, ponieważ nie ma sposobu na ograniczenie instancji klasy wewnątrz deklarującej biblioteki. Zawsze wymaga dyscypliny od autora biblioteki. W twoim przykładzie biblioteka deklarująca może wywoływać new Singleton._internal()tyle razy, ile chce, tworząc wiele obiektów Singletonklasy. Jeśli Implklasa w przykładzie Andrew była prywatna ( _Impl), byłaby taka sama jak twój przykład. Z drugiej strony singleton jest anty-wzorem i nikt nie powinien go używać.
Ladicek
@Ladicek, czy nie ufasz twórcom biblioteki, że nie będą nazywać nowych Singelton._internal(). Można argumentować, że twórcy klasy singelton mogliby również zainicjować klasę kilka razy. Pewnie, że istnieje enum singelton, ale dla mnie jest to tylko zastosowanie teoretyczne. Wyliczenie jest wyliczeniem, a nie pojedynczym ... Jeśli chodzi o użycie zmiennych najwyższego poziomu (@Andrew i @Seth): Czy nikt nie mógłby pisać do zmiennej najwyższego poziomu? W żadnym wypadku nie jest chroniony, czy coś mi brakuje?
Tobias Ritzau
12
Oto inny możliwy sposób:
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;}
Cześć, a może coś takiego? Bardzo prosta implementacja, sam Injector jest singletonem, a także dodaje do niego klasy. Oczywiście można go bardzo łatwo przedłużyć. Jeśli szukasz czegoś bardziej zaawansowanego, sprawdź ten pakiet: https://pub.dartlang.org/packages/flutter_simple_dependency_injection
Nie publikuj pytań uzupełniających jako odpowiedzi. Problem z tym kodem polega na tym, że jest trochę zbyt szczegółowy. static GlobalStore get instance => _instance ??= new GlobalStore._();zrobiłaby. Co _(){}ma robić? To wydaje się zbędne.
Günter Zöchbauer
przepraszam, to była sugestia, a nie kolejne pytanie, _ () {} stworzy prywatnego konstruktora, prawda?
Vilsad PP
Konstruktory zaczynają się od nazwy klasy. Jest to zwykła metoda instancji prywatnej bez określonego typu zwrotu.
Günter Zöchbauer
1
Przepraszam za opinię, ale myślę, że jest złej jakości i nie dodaje żadnej wartości oprócz istniejących odpowiedzi.
Günter Zöchbauer
2
Chociaż ten kod może odpowiedzieć na pytanie, zapewnienie dodatkowego kontekstu dotyczącego tego, jak i / lub dlaczego rozwiązuje problem, poprawiłoby długoterminową wartość odpowiedzi.
Karl Richter
0
Ponieważ nie lubię używać newsłowa kluczowego lub innego konstruktora, takiego jak wywołania singletonów, wolałbym użyć statycznego gettera o nazwie instna przykład:
// the singleton classclassDao{// singleton boilerplateDao._internal(){}staticfinalDao _singleton =newDao._internal();staticget inst => _singleton;// business logicvoid greet()=> print("Hello from singleton");}
przykładowe użycie:
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));
Odpowiedzi:
Dzięki fabrycznym konstruktorom Dart łatwo jest zbudować singletona:
Możesz to zbudować w ten sposób
źródło
new
nie oznacza tutaj „skonstruowania nowego”, a jedynie „uruchom konstruktora”.new
Kluczowe sugeruje, że klasa jest instancja, która nie jest. Wybrałbym metodę statycznąget()
lubgetInstance()
jak ja w Javie.Singleton._internal();
która wygląda jak wywołanie metody, gdy jest to naprawdę definicja konstruktora. Tam jest_internal
nazwa. Jest też sprytny projektowy język, w którym Dart pozwala rozpocząć (rzutem?) Za pomocą zwykłego konstruktora, a następnie, w razie potrzeby, zmienić go nafactory
metodę bez zmiany wszystkich wywołujących.Oto porównanie kilku różnych sposobów na utworzenie singletona w Dart.
1. Konstruktor fabryki
2. Pole statyczne z geterem
3. Pole statyczne
Jak zainicjować
Powyższe singletony są tworzone w następujący sposób:
Uwaga:
Początkowo zadałem to pytanie , ale odkryłem, że wszystkie powyższe metody są prawidłowe, a wybór w dużej mierze zależy od osobistych preferencji.
źródło
static final SingletonThree instance = SingletonThree()
. To samo dotyczy drugiego sposobu_instance
. Nie wiem, co jest wadą nieużywania prywatnego konstruktora. Jak dotąd nie mam żadnych problemów. Drugi i trzeci sposób i tak nie blokują wywołania domyślnego konstruktora.SingletonThree instance2 = SingletonThree()
. Jeśli spróbujesz to zrobić, gdy istnieje prywatny konstruktor, pojawi się błąd:The class 'SingletonThree' doesn't have a default constructor.
Nie uważam tego za bardzo intuicyjne czytanie
new Singleton()
. Musisz przeczytać dokumenty, aby wiedzieć, żenew
tak naprawdę nie tworzy nowej instancji, jak zwykle.Oto inny sposób na tworzenie singletonów (w zasadzie to, co Andrew powiedział powyżej).
lib / thing.dart
main.dart
Zauważ, że singleton nie zostanie utworzony do pierwszego wywołania gettera z powodu leniwej inicjalizacji Dart.
Jeśli wolisz, możesz także zaimplementować singletony jako statyczny getter w klasie singletonów. tj.
Thing.singleton
zamiast getter najwyższego poziomu.Przeczytaj także wypowiedź Boba Nystroma dotyczącą singletonów ze swojej książki wzorców programowania gier .
źródło
Co powiesz na takie użycie globalnej zmiennej w bibliotece?
single.dart
:main.dart
:A może to się marszczy?
Wzorzec singletonu jest konieczny w Javie, w której nie istnieje koncepcja globałów, ale wydaje się, że nie powinieneś iść daleko w Dart.
źródło
Singleton
. W moim przykładzie powyżejSingleton
klasa jest prawdziwym singletonem, tylko jedna instancjaSingleton
może kiedykolwiek istnieć w izolatce.new Singleton._internal()
tyle razy, ile chce, tworząc wiele obiektówSingleton
klasy. JeśliImpl
klasa w przykładzie Andrew była prywatna (_Impl
), byłaby taka sama jak twój przykład. Z drugiej strony singleton jest anty-wzorem i nikt nie powinien go używać.Singelton._internal()
. Można argumentować, że twórcy klasy singelton mogliby również zainicjować klasę kilka razy. Pewnie, że istnieje enum singelton, ale dla mnie jest to tylko zastosowanie teoretyczne. Wyliczenie jest wyliczeniem, a nie pojedynczym ... Jeśli chodzi o użycie zmiennych najwyższego poziomu (@Andrew i @Seth): Czy nikt nie mógłby pisać do zmiennej najwyższego poziomu? W żadnym wypadku nie jest chroniony, czy coś mi brakuje?Oto inny możliwy sposób:
źródło
Dart Singleton firmy Const Konstruktor i fabryka
źródło
Singleton, który nie może zmienić obiektu po instancji
źródło
Zmodyfikowano odpowiedź @Seth Ladd, która preferuje szybki styl singletonu, taki jak
.shared
:Próba:
źródło
Po przeczytaniu wszystkich alternatyw wymyśliłem to, co przypomina mi „klasyczny singleton”:
źródło
getInstance
metodę w takiejinstance
nieruchomości:static AccountService get instance => _instance;
Oto prosta odpowiedź:
źródło
Oto zwięzły przykład, który łączy inne rozwiązania. Dostęp do singletonu można uzyskać poprzez:
singleton
zmiennej globalnej, która wskazuje na instancję.Singleton.instance
wzór.Uwaga: Należy zaimplementować tylko jedną z trzech opcji, aby kod korzystający z singletonu był spójny.
Jeśli potrzebujesz skomplikowanej inicjalizacji, musisz to zrobić przed użyciem instancji później w programie.
Przykład
źródło
Cześć, a może coś takiego? Bardzo prosta implementacja, sam Injector jest singletonem, a także dodaje do niego klasy. Oczywiście można go bardzo łatwo przedłużyć. Jeśli szukasz czegoś bardziej zaawansowanego, sprawdź ten pakiet: https://pub.dartlang.org/packages/flutter_simple_dependency_injection
źródło
To powinno działać.
źródło
static GlobalStore get instance => _instance ??= new GlobalStore._();
zrobiłaby. Co_(){}
ma robić? To wydaje się zbędne.Ponieważ nie lubię używać
new
słowa kluczowego lub innego konstruktora, takiego jak wywołania singletonów, wolałbym użyć statycznego gettera o nazwieinst
na przykład:przykładowe użycie:
źródło