Wzorzec Singleton
Część sekcji Programowanie obiektowe ścieżki Dart w Coddy. Lekcja 90 z 110.
Wzorzec Singleton gwarantuje, że klasa ma tylko jedną instancję w całej aplikacji, i zapewnia globalny punkt dostępu do niej. Jest to przydatne, gdy do koordynowania działań w całym systemie potrzebny jest dokładnie jeden obiekt — na przykład menedżer konfiguracji, połączenie z bazą danych lub usługa logowania.
W Dart możesz zaimplementować wzorzec Singleton za pomocą konstruktora factory połączonego z prywatną instancją statyczną:
class AppConfig {
static final AppConfig _instance = AppConfig._internal();
String appName = 'MyApp';
String version = '1.0.0';
// Prywatny konstruktor nazwany
AppConfig._internal();
// Konstruktor fabryczny zwraca tę samą instancję
factory AppConfig() {
return _instance;
}
}
void main() {
var config1 = AppConfig();
var config2 = AppConfig();
config1.appName = 'UpdatedApp';
print(config2.appName); // UpdatedApp
print(identical(config1, config2)); // true
}Prywatny konstruktor _internal() uniemożliwia tworzenie instancji z zewnątrz. Pole statyczne _instance przechowuje jedyną instancję, utworzoną raz podczas ładowania klasy. Każde wywołanie AppConfig() zwraca tę samą instancję, więc zmiany wprowadzone za pomocą jednego odwołania są widoczne wszędzie.
Używaj wzorców Singleton oszczędnie — wprowadzają stan globalny, co może utrudnić testowanie. Najlepiej sprawdzają się w przypadku zasobów współdzielonych, które muszą zachowywać spójny stan w całej aplikacji.
Wyzwanie
ŁatwyStwórzmy menedżera ustawień gry, używając wzorca Singleton! Utworzysz system, który zapewnia, że w całej aplikacji istnieje tylko jedna instancja ustawień gry, dzięki czemu wszystkie części gry korzystają z tej samej konfiguracji.
Podzielisz kod na dwa pliki:
game_settings.dart: Utwórz klasęGameSettings, która implementuje wzorzec Singleton. Menedżer ustawień powinien mieć:- Prywatną statyczną instancję final, która przechowuje jedyny obiekt
GameSettings - Prywatny konstruktor nazwany, który zapobiega tworzeniu instancji z zewnątrz
- Konstruktor fabryczny, który zawsze zwraca tę samą instancję
- Trzy pola ustawień:
difficulty(String, wartość domyślna: "Normal"),soundEnabled(bool, wartość domyślna: true) iplayerName(String, wartość domyślna: "Player1") - Metodę
displaySettings(), która wyświetla bieżące ustawienia w tym formacie:Settings: [playerName] | Difficulty: [difficulty] | Sound: [on/off](wyświetl "on", jeśli soundEnabled ma wartość true, a "off", jeśli ma wartość false)
- Prywatną statyczną instancję final, która przechowuje jedyny obiekt
main.dart: Zaimportuj ustawienia gry i pokaż, że Singleton działa poprawnie:- Pobierz instancję ustawień i nazwij ją
settings1 - Wywołaj
displaySettings(), aby wyświetlić wartości domyślne - Zmień ustawienia: ustaw
playerNamena "Hero",difficultyna "Hard", asoundEnabledna false - Pobierz kolejne odwołanie do ustawień i nazwij je
settings2 - Wywołaj
displaySettings()dlasettings2, aby potwierdzić, że odzwierciedla zmiany wprowadzone za pomocąsettings1 - Wyświetl informację, czy
settings1isettings2są identyczne, używając formatu:Same instance: [true/false]
- Pobierz instancję ustawień i nazwij ją
To pokazuje główną zaletę wzorca Singleton — zmiany wprowadzone w dowolnym miejscu aplikacji są natychmiast widoczne wszędzie indziej, ponieważ istnieje tylko jedna instancja!
Oczekiwany wynik:
Settings: Player1 | Difficulty: Normal | Sound: on
Settings: Hero | Difficulty: Hard | Sound: off
Same instance: trueSpróbuj swoich sił
import 'game_settings.dart';
void main() {
// TODO: Pobierz instancję ustawień i nazwij ją settings1
// TODO: Wywołaj displaySettings(), aby wyświetlić wartości domyślne
// TODO: Zmodyfikuj ustawienia:
// - Zmień playerName na "Hero"
// - Zmień difficulty na "Hard"
// - Zmień soundEnabled na false
// TODO: Pobierz kolejne odwołanie do ustawień i nazwij je settings2
// TODO: Wywołaj displaySettings() na settings2, aby pokazać, że odzwierciedla zmiany
// TODO: Wyświetl, czy settings1 i settings2 są identyczne
// Format: Same instance: [true/false]
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy OOP
Pliki zewnętrzneBiblioteki i importyWprowadzenie do OOPKlasy a obiektySłowo kluczowe thisMetodyZmienne instancjiPodstawy konstruktorówPowtórka – prosty kalkulator4Bezpieczeństwo wartości null
Wprowadzenie do bezpieczeństwa wartości nullTypy dopuszczające null i niedopuszczające nullOperatory ? i !Słowo kluczowe late a bezpieczeństwo wartości nullOperatory uwzględniające nullBezpieczeństwo wartości null w klasachPodsumowanie — system profili użytkowników7Klasy abstrakcyjne i interfejsy
Klasy abstrakcyjneMetody abstrakcyjneInterfejsy w DartInterfejsy niejawneImplementowanie a rozszerzanieWiele interfejsówPowtórka — kalkulator kształtów10Kolekcje i typy generyczne
Przegląd List, Set i MapKolekcje bezpieczne typowoKlasy generyczneMetody generyczneOgraniczenia typów generycznychIterable i IteratorPowtórka — generyczne przechowywanie danych13Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieMetody rozszerzająceKlasy wywoływalneKlasy zapieczętowane (Dart 3)Rekordy (Dart 3)Wzorce i dopasowywanie (3.0)Typy wyliczeniowe z metodami16Projekt: Zarządzanie biblioteką
Omówienie projektuKlasy książek i użytkowników2Konstruktory w Dart
Konstruktor domyślnyKonstruktory nazwaneListy inicjalizująceKonstruktory stałeKonstruktory fabryczneKonstruktory przekierowującePodsumowanie — budowanie kształtów5Hermetyzacja
Elementy publiczne a prywatneKonwencja prefiksu _Prywatność na poziomie bibliotekiGettery i settery — szczegółowoUkrywanie informacjiPodsumowanie — dane uczniów8Domieszki
Wprowadzenie do domieszekTworzenie domieszekKorzystanie z wielu domieszekSłowo kluczowe on w domieszkachDomieszka a dziedziczenieDomieszka a interfejsPodsumowanie – system zwierząt11Metody specjalne
Nadpisanie toString()Nadpisanie hashCode i ==Interfejs ComparableMetoda call()Nadpisanie noSuchMethodPodsumowanie — własna kolekcja14Wzorce projektowe, część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec Strategy3Właściwości klas
Elementy instancji a elementy statycznePola final i constZmienne inicjalizowane z opóźnieniemMetody i pola statyczneGettery i setteryPowtórzenie – menedżer kont bankowych6Dziedziczenie
Podstawy dziedziczeniaSłowo kluczowe superPrzesłanianie metodAdnotacja @overrideSłowo kluczowe final dla klasKonstruktory i dziedziczeniePowtórzenie – hierarchia pracowników9Polimorfizm
Podstawy polimorfizmuPolimorfizm za pomocą interfejsówSprawdzanie typu w czasie działaniaOperatory is i asSłowo kluczowe covariantPodsumowanie — procesor płatnościPoćwicz samodzielnie: Kompilator Dart online