Wzorce projektowe – singleton

UWAGA, ruszył Humble Book Bundle: DevOps - jak zwykle pierwszy próg 5 książek od $1, cały komplet od $15.

Singleton – jeden ze wzorców konstrukcyjnych. Jego celem jest zapewnienie możliwości utworzenia tylko jednego obiektu danej klasy i zapewnienie do niego globalnego dostępu.

Przez wielu uważany za antywzorzec, głównie ze względu na ograniczoną możliwość testowania kodu. Pomijając kwestie słuszności jego wykorzystania przedstawię jego poprawną implementację, co nie jest trywialne jakby mogło się wydawać.

Klasa z implementacją singletona zawiera:

  • statyczną zmienną przechowującą instancję tej klasy,
  • prywatny „pusty” konstruktor (aby nie można było utworzyć nowego obiektu tej klasy z wykorzystaniem operatora „new”),
  • publiczną statyczną metodę „getInstance” bez żadnych parametrów.

W języku PHP implementacja jest dosyć prosta i może być następująca:

W języku Java nie jest już tak łatwo. Należy obsłużyć ewentualną wielowątkowość.

  1. Klasyczna implementacja (błędna, nieobsługiwana wielowątkowość).

    W przypadku wielowątkowego dostępu problem jest w liniach 10 i 11. Przykład:

    • wątek A sprawdza czy instance == null (prawda)
    • w tym samym czasie wątek B również sprawdza ten warunek przed utworzeniem obiektu przez wątek A w linii 11
    • wątek B tworzy drugi obiekt singletona.
  2. Implementacja z synchronizowanym dostępem

    Ta implementacja jest poprawna, ale kosztowna, a synchronizacja dostępu do metody konieczna jest tylko podczas pierwszego użycia tej metody. Dlatego lepszą wersją synchronizowanego dostępu będzie kolejna implementacja.

  3. Implementacja z ‚podwójnym blokowaniem’ (dla Javy >= 1.5).

    W tej implementacji synchronizacja ma miejsce tylko przy pierwszym wywołaniu metody. Jeżeli dwa wątki równocześnie wywołają metodę getInstance i pierwszy warunek (instance == null) zostanie spełniony przez nie oba, to w kolejnej linii (synchronized (Singleton.class)) dostęp do ponownego sprawdzenia warunku (instance == null) zostanie zsynchronizowany. W efekcie czego jeden z wątków utworzy nową instancję, a drugi już go pobierze nie wchodząc w warunek z linii 12.
    Kluczową kwestią jest tu słowo kluczowe volatile. Powoduje ono, że zmienna instance będzie prawidłowo traktowana kiedy następuje przypisywanie do niej nowo utworzonej instancji obiektu (w programie wielowątkowym). Przykład:

    • wątek A zauważa niezainicjowaną zmienną, uzyskuje blokadę i rozpoczyna inicjalizować zmienną
    • środowisko może zaktualizować współdzieloną zmienną częściowo utworzonego obiektu zanim wątek A zakończy inicjalizację
    • wątek B zauważa że zmienna została zainicjowana i pomija synchronizowany blok

    Jest to niuans, który może doprowadzić do poważnych błędów, a ich wykrycie jest bardzo trudne.

  4. Implementacja z prywatną klasą statyczną (Bill Pugh)


    Jest to najlepsza implementacja singletona. Należy zwrócić uwagę, że gdy klasa Singleton zostanie załadowana, klasa SingletonHolder nie zostanie wczytana do pamięci dopóki nie zostanie wywołana metoda getInstance(). Takie podejście nie wymaga synchronizacji, jest łatwe do zrozumienia i zaimplementowania.

UWAGA, ruszył Humble Book Bundle: DevOps - jak zwykle pierwszy próg 5 książek od $1, cały komplet od $15.

To również może Cię zainteresować:

  • Wzorce projektowe – dekoratoryWzorce projektowe – dekoratory Dekorator to jeden se strukturalnych wzorców projektowych, dzięki któremu możemy wykorzystać kompozycję w alternatywie do dziedziczenia w celu rozszerzenia zachowania klasy. W przypadku […]
  • Wzorce projektowe – fabrykiWzorce projektowe – fabryki Za każdym razem gdy używamy w kodzie operatora new, uzależniamy się od konkretnej implementacji zamiast od interfejsu. Jedna z zasad programowania obiektowego (reguła odwracania zależności […]
  • Permutacje, cz. 2 – algorytmyPermutacje, cz. 2 – algorytmy W poprzednim wpisie programistyczne rozwiązanie zagadki polegało na wygenerowaniu wszystkich permutacji zbioru i sprawdzeniu każdej z nich pod względem spełnienia warunku […]
  • Java JNA #2, Total CommanderJava JNA #2, Total Commander W poprzednim wpisie zrobiłem krótkie wprowadzenie do wykorzystywania biblioteki user32.dll przez Javę do pobierania informacji z innych aplikacji okienkowych. Poniżej rozszerzymy nasze […]
  • Czat z socket.io i JavaCzat z socket.io i Java Cel: Oprogramowanie w javie chatu działającego w czasie rzeczywistym bez komunikacji asynchronicznej. Biblioteki: socket.io netty-socketio Efekt […]
  • 10-letni chłopak zdobył 100% na egzaminie OCPJP z Javy!10-letni chłopak zdobył 100% na egzaminie OCPJP z Javy! W zeszłym roku Ronil Shah zaskoczył prawie wszystkich zdobywając sto procent punktów w egzaminie z Javy OCPJP. Jednak to nie wszystko. Najciekawsze jest to, że egzamin ten przewidziany […]

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *