Singleton – kreacyjny wzorzec projektowy, dający pewność, że klasa ma tylko jedną, globalnie dostępną instancję.
Przeznaczenie i warunki stosowania
Warunki jakie należy spełnić aby używać wzorca:
- Musi istnieć dokładnie jeden egzemplarz klasy udostępniany klientom
- W przypadku rozszerzenia jedynej klasy przez stworzenie podklas, klienci powinno nadal móc korzystać bez wprowadzania zmian w swoim kodzie.
Singleton może zostać wykorzystany do implementacji innych wzorców (o czym w kolejnych wpisach):
- Budowniczy,
- Fabryka Abstrakcyjna,
- Prototyp.
Życiowa analogia
Dyrekcja szkoły. Szkoła może mieć tylko jedną dyrekcję. Niezależnie od osób w dyrekcji, tytuł „Dyrekcja szkoły” jest globalnym punktem dostępu do Dyrekcji i dotyczy zawsze tej samej dyrekcji (w przestrzeni danej szkoły).
Singleton Struktura
- Definiuje operację
GetInstance()
umożliwiającą dostęp do niepowtarzalnego egzemplarza klasy - Odpowiada za tworzenie własnego niepowtarzalnego egzemplarza
Singleton Konsekwencje Stosowania
Pozytywne:
- zapewnia kontrolę dostępu do jedynego egzemplarza
- obiekt jest tworzony dopiero gdy zostanie zażądany po raz pierwszy
- pozwala zmniejszyć przestrzeń nazw – ogranicza zaśmiecanie przestrzeni nazw zmiennymi globalnymi
- umożliwia określenie limitu egzemplarzy (domyślnie 1) – wystarczy zmodyfikować operację
GetInstance()
Negatywne
I tutaj ukazuje się prawdziwe oblicze Singletonu:
- łamanie dobrych praktyk SOLID (szczególnie *S* – single responsibility principle, czyli zasada pojedynczej odpowiedzialności)
- nie istnieje dobry sposób „zniszczenia” lub zwolnienia Singletonu
- utrudnione testowanie (szczególnie w przypadku aplikacji wielowątkowych)
- stosowanie go jako zamiennik zmiennej globalnej
- klasa dziedzicząca z Singletonu, nie jest Singletonem, potrzebny jest dodatkowy kod
- w większości wywołań metody
GetInstance()
, instrukcjaif(null)
jest bezużyteczna, co może odbijać się na wydajności przy wielu wywołaniach
Singleton Implementacja
W najprostszym wydaniu implementacja wzorca Signleton, opiera się o:
- Prywatne statyczne pole reprezentujące żądany obiekt (line 4).
- Publiczną statyczną metodę zwracającą jedyną instancję klasy, tworzącą ją w przypadku jej braku (line 6).
W bardziej rozbudowanych modelach, można spotkać również:
1. Blokadę wątku, przed stworzeniem nowej instancji klasy (patrz linia 10). Zabezpiecza to nasz model przed równoczesnym wywołaniem GetInstance()
przez dwa wątki w tym samym czasie i ponownego stworzenia/nadpisania obiektu (tutaj loggera).
2. „Ukryty” konstruktora klasy: protected SingletonLoggerExample()
– blokując możliwość tworzenia obiektu przez domyślny konstruktor publiczny.
3. Rzucanie wyjątkiem w prywatnym w powyższym konstruktorze, uniemożliwiając przypadkowe wywołanie go z wykorzystaniem refleksji.
Podsumowanie
Niewątpliwie Singleton jest dobrym materiałem treningowym do zrozumienia zagadnień związanych z programowaniem, jednak nie cieszy się powodzeniem wśród doświadczonych programistów. Głównie ze względu na negatywne konsekwencje jakie ze sobą niesie jego implementacja.
Prostym i dość oczywistym przykładem prawidłowego zastosowania wzorca jest prosty logger. Niestety może się to zmienić w przypadku bardziej złożonych schematów rejestrowania.
Ważne abyś samemu zastanowił się i przemyślał, czy Singleton to wzorzec który pasuje do Twojego problemu, czy może inny Wzorzec Projektowy byłby lepszy, a może prosty kod będzie wystarczający?
Zainteresował Cię materiał? Zapraszam do listy mailowej, by być na bieżąco z kolejnymi wpisami.