Singleton
Wzorzec kreacyjny dzieki któremu możesz być pewny, że istnieje tylko pojedyńcza instancja danej klasy. Zapewnia również dostęp do tej instancji w zakresie całej aplikacji.
Singleton łamie zasade pojedyńczej odpowiedzialności rozwiązując dwa problemy jednocześnie:
- Zapewnia istnienie tylko jednej instancji danej klasy.
Częstym powodem dla którego chcemy aby istniała tylko jedna instancja jest to że klasa zapewnia dostęp do jakiegoś zasobu, np.: bazy danych lub pliku. Używając singletona możemy kontrolować/ograniczać dostęp do współdzielonego zasobu lub konfiguracji aplikacji.
Zasada działania wzorca jest dosyć prosta. W momencie kiedy chcesz uzyskać dostęp do obiektu implementującego singleton, odpowiedzialna za niego klasa sprawdza czy nie został już stworzony, jeśli tak - zwróci istniejącą instancje, w innym przypadku utworzy nową. Implementacja takiego zachowania nie jest możliwa z użyciem zwykłego konstruktora ponieważ ten zgodnie z zasadami designu zawsze musi zwrócić nowy obiekt - jak poprawnie zaimplementować singleton opisuje poniżej.
- Udostępnia globalny sposób dostępu do tej pojedyńczej instancji.
Podobnie jak zmienne globalne, wzorzec singleton pozwala Ci uzyskać dostęp do danego obiektu z dowolnego miejsca w aplikacji. Przewagą wzorca nad globalnymi zmiennymi jest ochrona instancji obiektu przed nadpisaniem go innym fragmentem kodu.
Kolejną zaletą tego rozwiązania jest to, że nie musisz kopiować kodu który rozwiązuje problem nr 1 do wielu fragmentów aplikacji, a pozostaje on w jednej klasie.
- Ze względu na popularność wzorca, często spotykanym jest nazywanie czegoś Singletonem nawet jeśli rozwiązuje tylko jeden z wymienionych wyżej problemów.
Jak zaimplementować singleton:
- Dodaj do klasy prywatne pole które będzie przechowywać instancje singletona
- Zadeklaruj publiczną metodę która będzie zwracać instancje singletona
- W tej publicznej metodzie zaimplementuj kod który przy pierwszym wywołaniu utworzy nowy obiekt i zapisze go w prywantmy polu, a przy następnych zwróci istniejącą instancje.
- Konstruktor tej klasy powinien być prywatny. W ten sposób dostęp do niego będze miała publiczna metoda odpowiedzialna za zwrócenie singletona, ale nie inne obiekty.
- W kodzie klienckim używaj publicznej metody by uzyskać dostęp do instancji singletona.
Zalety i wady:
- Możesz być pewny że klasa będzie miała tylko pojedyńczą instancje.
- Zyskujesz globalny sposób na dostęp do tej instancji.
-
Obiekt tej klasy jest inicjalizowany dopiero przy pierwszej próbie uzyskania dostępu.
- Wzorzec łamie zasade pojedyńczej odpowiedzialności - rozwiązuje dwa problemy.
- Może maskować zły design, np.: gdy różne części aplikacji wiedzą zbyt dużo o sobie nawzajem.
- Wymaga dodatkowej uwagi w środowisku wielowątkowym, by nie dopuścić do utworzenia obiektu singleton wiele razy.
- Testy jednostkowe takiego obiektu mogą być problematyczne. Ze względu na prywatny konstruktor wiele frameworków testowych będzie miało problem z utworzeniem mocku.
Przykładowy kod: https://github.com/rafczow/php-patterns-practice/tree/master/src/Singleton
Powiązane wzorce: Facade Flyweight