CodeGym /Blog Java /Random-PL /Wzorce i Singleton w Javie
Autor
Jesse Haniel
Lead Software Architect at Tribunal de Justiça da Paraíba

Wzorce i Singleton w Javie

Opublikowano w grupie Random-PL
Ten artykuł jest skierowany do każdego, kto po raz pierwszy spotyka się z koncepcją wzorców projektowych, słyszał termin singleton lub w jakiś sposób zaimplementował wzorzec singleton, ale nie rozumiał, co się dzieje. Powitanie! Uczniowie CodeGym po raz pierwszy spotykają się z wzorcami projektowymi na poziomie 15, kiedy kapitan nieoczekiwanie prosi ich o „wzmocnienie” ich zrozumienia poprzez wdrożenie wzorca Java Singleton z leniwą implementacją. Studenci , którzy po raz pierwszy słyszą o wzorcu singleton , od razu mają mnóstwo pytań: czym, u licha, jest wzorzec projektowy? Dlaczego tego potrzebujemy? Co to jest singleton ? I wreszcie, czym jest leniwa implementacja? Odpowiedzmy na te pytania po kolei.

Czym, u licha, jest wzorzec projektowy?

Wierzę, że trochę historii jest po to, aby odpowiedzieć na to pytanie z najlepszym zrozumieniem. Istnieje czterech znanych autorów programistycznych (Erich Gamma, John Vlissides, Ralph Johnson i Richard Helm), którzy wpadli na ciekawy pomysł. Zauważyli, że tworzenie oprogramowania często wymagało od nich rozwiązywania w przybliżeniu tych samych problemów i pisania kodu o tej samej strukturze. Postanowili więc opisać typowe wzorce, które często muszą być stosowane w programowaniu obiektowym. Ich książka została opublikowana w 1994 roku pod tytułem Design Patterns: Elements of Reusable Object-Oriented Software. Nazwa książki okazała się zbyt długa i ludzie zaczęli nazywać ją po prostu książką Gang of Four. Pierwsza edycja obejmowała 23 wzory. Później odkryto dziesiątki innych wzorów.
Wzorzec projektowy to standardowe rozwiązanie typowego problemu.
A wzorzec singleton jest tylko jednym z nich.

Po co nam wzorce projektowe?

Możesz programować bez znajomości wzorców: w końcu na poziomie 15 napisałeś już setki mini-programów w CodeGym, nawet nie wiedząc, że one istnieją. Sugeruje to, że wzorce projektowe są rodzajem narzędzia, którego użycie odróżnia mistrza od amatora: Wzorce projektowe opisują, jak prawidłowo rozwiązać typowy problem. Oznacza to, że znajomość wzorców oszczędza czas. Pod tym względem są podobne do algorytmów. Na przykład możesz stworzyć własny algorytm sortowania z blackjackiem i liczbamii poświęcić na to dużo czasu, lub możesz wdrożyć taki, który był rozumiany i opisywany przez długi czas. To samo dotyczy wzorców projektowych. Ponadto dzięki wzorcom projektowym kod staje się bardziej standardowy, a użycie odpowiedniego wzorca zmniejsza prawdopodobieństwo popełnienia błędów, ponieważ typowe pułapki wzorca zostały zidentyfikowane i wyeliminowane dawno temu. Oprócz wszystkiego, znajomość wzorców pomaga programistom lepiej się zrozumieć. Możesz po prostu powiedzieć nazwę wzorca, zamiast próbować podać obszerne wyjaśnienie swoim kolegom programistom. Podsumowując, wzorce projektowe pomagają:
  • nie wymyślać koła na nowo, ale korzystać ze standardowych rozwiązań;
  • standaryzować kod;
  • ujednolicić terminologię;
Na zakończenie tej sekcji zauważamy, że cały zbiór wzorców projektowych można podzielić na trzy duże grupy: Wzory i singleton - dla wszystkich, którzy spotykają się z nimi po raz pierwszy - 2

Wreszcie wzór singletona

Singleton jest wzorcem kreacyjnym . Ten wzorzec zapewnia, że ​​istnieje tylko jedno wystąpienie klasy i zapewnia globalny punkt dostępu dla tego obiektu. Z opisu powinno być jasne, że ten wzór należy zastosować w dwóch przypadkach:
  1. gdy program wymaga utworzenia nie więcej niż jednego obiektu określonej klasy. Na przykład gra komputerowa może mieć klasę Hero i tylko jeden obiekt Hero, który opisuje jedynego bohatera w grze.

  2. gdy trzeba zapewnić punkt globalnego dostępu do obiektu. Innymi słowy, musisz udostępnić obiekt z dowolnego miejsca w programie. Niestety, nie wystarczy po prostu utworzyć zmiennej globalnej, ponieważ nie jest ona chroniona przed zapisem: każdy może zmienić wartość zmiennej, więc globalny punkt dostępu do obiektu może zostać utracony. Te właściwości Singletona niezbędne, na przykład, gdy masz obiekt współpracujący z bazą danych i potrzebujesz dostępu do bazy danych z różnych części programu. Singleton sprawi, że nikt nie napisze kodu, który zastąpi wcześniej utworzoną instancję .
Tak więc Singleton spełniał te dwie potrzeby: w programie musi być tylko jeden obiekt określonego rodzaju i musi istnieć do niego globalny dostęp. W przykładzie na poziomie 15 kapitan prosi o zaimplementowanie tego wzorca dla następującego zadania:
  1. Znajdź przykład Singletona z leniwą inicjalizacją.

  2. Utwórz trzy pojedyncze klasy — Słońce, Księżyc, Ziemia — w oddzielnych plikach, korzystając z tej samej zasady.

  3. Wprowadzić w życiePlanetainterfejs w klasach Sun , Moon i Earth .

  4. W statycznym bloku klasy Solution wywołaj metodęreadKeyFromConsoleAndInitPlanetmetoda.

  5. WdrożyćreadKeyFromConsoleAndInitPlanetfunkcjonalność metody:

    • 5.1. Odczytaj jeden parametr String z konsoli

    • 5.2. Jeśli parametr jest równy jednemu zPlanetastałych interfejsu, utwórz odpowiedni obiekt thePlanet .

Po uważnym przeczytaniu warunków zadania, możemy wyraźnie zobaczyć, dlaczego potrzebny jest tutaj Singleton . Rzeczywiście, jesteśmy proszeni o utworzenie instancji każdej z następujących klas: Sun , Moon , Earth . Sensowne jest założenie, że powinniśmy stworzyć nie więcej niż jedno Słońce/Księżyc/Ziemię. W przeciwnym razie wpadamy w absurdalną sytuację, chyba że oczywiście piszesz swoją wersję Gwiezdnych Wojen. Implementacja wzorca Singleton w Javie w trzech krokach W Javie zachowania Singleton nie można zaimplementować za pomocą zwykłego konstruktora, ponieważ konstruktor zawsze zwraca nowy obiekt. Dlatego wszystkie implementacje Singletonsprowadza się do ukrycia konstruktora, stworzenia publicznej statycznej metody kontrolującej czas życia pojedynczego obiektu i „zniszczenia” wszystkich nowo pojawiających się obiektów. Jeśli uzyskuje się dostęp do Singletona , powinien on albo utworzyć nowy obiekt (jeśli taki jeszcze nie istnieje w programie), albo zwrócić istniejący. Aby to osiągnąć:
  1. Musisz nadać klasie prywatne pole statyczne, które przechowuje pojedynczy obiekt:

    
    public class LazyInitializedSingleton {
    	private static LazyInitializedSingleton instance; // #1
    }
    
  2. Uczyń (domyślnego) konstruktora prywatnym. Oznacza to, że nie można uzyskać do niego dostępu poza klasą i nie będzie w stanie zwrócić nowych obiektów:

    
    public class LazyInitializedSingleton {
    	private static LazyInitializedSingleton instance;
    private LazyInitializedSingleton(){} // #2
    } 
    
  3. Zadeklaruj statyczną metodę tworzenia, która zostanie użyta do uzyskania singletona:

    
    public class LazyInitializedSingleton {
        private static LazyInitializedSingleton instance;
            private LazyInitializedSingleton() {}
            public static LazyInitializedSingleton getInstance() { // #3
            if (instance == null) { // If the object has not yet been created
                instance = new LazyInitializedSingleton(); // Create a new object
            }
            return instance; // Return the previously created object
        }
    }
    
Powyższy przykład jest nieco niezgrabny, ponieważ po prostu ukrywamy konstruktora i udostępniamy własną metodę zamiast standardowego konstruktora. Ponieważ ten artykuł ma na celu upewnienie się, że uczniowie CodeGym zetkną się z tym wzorcem (i ogólnie wzorcami projektowymi), niuanse bardziej złożonych implementacji singletonowych nie będą tutaj opisywane. Zauważmy tylko, że w zależności od złożoności programu ten wzorzec może wymagać dalszego udoskonalenia. Na przykład w środowisku wielowątkowym (zobacz artykuły o wątkach) kilka różnych wątków może jednocześnie uzyskiwać dostęp do metody singleton, a opisany powyżej kod przestanie działać, ponieważ każdy oddzielny wątek może utworzyć instancję klasy. W rezultacie nadal istnieje kilka różnych podejść do tworzenia odpowiednich singletonów bezpiecznych dla wątków. Ale to już inna historia =)

I wreszcie... Co to za leniwa inicjalizacja, o którą pytał kapitan?

Inicjalizacja z opóźnieniem jest również nazywana inicjalizacją odroczoną. Jest to sztuczka programistyczna, w której operacja wymagająca dużej ilości zasobów (a tworzenie obiektu jest operacją wymagającą dużej ilości zasobów) jest wykonywana na żądanie, a nie z wyprzedzeniem. Co właściwie dzieje się w naszym kodzie Singleton Java? Innymi słowy, nasz obiekt jest tworzony w momencie uzyskania do niego dostępu, a nie z wyprzedzeniem. Nie należy zakładać, że leniwa inicjalizacja jest w jakiś sposób sztywno powiązana ze wzorcem Singletona . Leniwa inicjalizacja jest również używana w innych kreacyjnych wzorcach projektowych, takich jak Proxy i Factory Method, ale to też inna historia =)
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION