Wzorzec singletonu jest powszechnie używany, gdy potrzebny jest pojedynczy, współdzielony zasób, do którego można uzyskać dostęp globalnie, na przykład połączenie z bazą danych, rejestrator lub menedżer konfiguracji. Wymuszając pojedynczą instancję, umożliwia wielu częściom programu dostęp do tego samego obiektu i modyfikowanie go, promując spójność danych i zmniejszając potrzebę stosowania zmiennych globalnych. Singleton można wykorzystać jako pamięć podręczną obiektów, w której często używane lub kosztowne w tworzeniu obiekty są przechowywane i ponownie wykorzystywane w całej aplikacji. Takie podejście pomaga poprawić wydajność, unikając tworzenia i inicjowania zbędnych obiektów.
W tym artykule wyjaśnimy tworzenie singletonu i zademonstrujemy przykład stylizacji singletonu w programie C++.
Przykład 1: Tworzenie prostego singletonu z inicjalizacją Eager
Prosty singleton z wczesną inicjalizacją to wzorzec projektowy, który zapewnia utworzenie tylko jednej instancji klasy i jest ona tworzona chętnie podczas inicjalizacji statycznej.
Zademonstrujemy podstawowy fragment kodu umożliwiający utworzenie prostego singletonu z szybką inicjalizacją. Zacznijmy od programu:
#include
klasa Singleton {
prywatny :
statyczny Singel * instancja ;
Singel ( ) { }
publiczny :
statyczny Singel * uzyskac instancje ( ) {
powrót instancja ;
}
} ;
Singel * Singel :: instancja = nowy Singleton ( ) ;
wew główny ( ) {
Singel * pojedyncza instancja 1 = Singel :: uzyskac instancje ( ) ;
Singel * pojedyncza instancja2 = Singel :: uzyskac instancje ( ) ;
st :: cout << 'singletonletonInstancja 1: ' << pojedyncza instancja 1 << st :: koniec ;
st :: cout << 'singletonletonInstance2: ' << pojedyncza instancja2 << st :: koniec ;
powrót 0 ;
}
Kod zawiera nagłówek
Po dołączeniu pliku nagłówkowego definiujemy klasę „Singleton”, która reprezentuje implementację wzorca singletonu. Posiada prywatny konstruktor i prywatną statyczną zmienną składową o nazwie „instancja”.
Następnie funkcja getInstance() jest implementowana jako publiczna statyczna funkcja składowa klasy „Singleton”. Zwraca instancję singletonu przechowywaną w instancji statycznej zmiennej składowej. Instancja statycznej zmiennej składowej jest zdefiniowana i inicjowana poza klasą za pomocą „Singleton* Singleton::instance = new Singleton();”. Ta linia inicjuje instancję klasy „Singleton” podczas inicjalizacji statycznej.
W funkcji main() deklarujemy dwa wskaźniki „singletonInstance1” i „singletonInstance2” i przypisujemy wartość, która jest zwracana poprzez wywołanie metody Singleton::getInstance(). Ponieważ instancja jest inicjowana chętnie, oba wskaźniki wskazują na tę samą instancję. Instrukcje „std::cout” wypisują adresy pamięci „singletonInstance1” i „singletonInstance2” na konsoli za pomocą operatora „<<” i „std::endl”.
Kod kończy się „returnem 0”, co oznacza pomyślne wykonanie programu.
Po uruchomieniu tego kodu wynik będzie mniej więcej taki:
Dane wyjściowe wyświetlają adresy pamięci „singletonInstance1” i „singletonInstance2”. Ponieważ obydwa wskaźniki mają przypisaną tę samą instancję, którą uzyskano z Singleton::getInstance(), mają ten sam adres pamięci. To pokazuje, jak wzorzec singletonu gwarantuje, że istnieje pojedyncza instancja klasy i że przyszłe wywołania metody getInstance() zawsze będą skutkować tą samą instancją.
Przykład 2: Implementacja wzorca Singleton z leniwą inicjalizacją
Ta demonstracja wyjaśnia implementację wzorca singletonu z leniwą inicjalizacją i pokazuje jego użycie w funkcji main(). Wyjaśnienie krok po kroku fragmentu kodu znajduje się po tym programie:
#includeklasa Singleton {
prywatny :
statyczny Singel * instancja ;
Singel ( ) {
st :: cout << „Utworzono instancję Singleton.” << st :: koniec ;
}
publiczny :
statyczny Singel * uzyskac instancje ( ) {
Jeśli ( instancja == nullptr ) {
instancja = nowy Singleton ( ) ;
}
powrót instancja ;
}
próżnia Pokaż wiadomość ( ) {
st :: cout << „Witam z Singleton!” << st :: koniec ;
}
~Singleton ( ) {
st :: cout << „Instancja Singleton zniszczona.” << st :: koniec ;
}
} ;
Singel * Singel :: instancja = nullptr ;
wew główny ( ) {
Singel * pojedyncza instancja 1 = Singel :: uzyskac instancje ( ) ;
pojedyncza instancja 1 -> Pokaż wiadomość ( ) ;
Singel * pojedyncza instancja2 = Singel :: uzyskac instancje ( ) ;
pojedyncza instancja2 -> Pokaż wiadomość ( ) ;
powrót 0 ;
}
Program rozpoczyna się od dodania pliku nagłówkowego
Za każdym razem, gdy wywoływany jest konstruktor klasy „Singleton”, generuje on instancję klasy „Singleton”. Wysyła do konsoli komunikat „Utworzono instancję Singleton” za pomocą „std::cout << … << std::endl;”. Konstruktor nie ma żadnych parametrów, ponieważ jest konstruktorem domyślnym. Jest ona zdefiniowana jako Singleton() bez żadnych argumentów. Deklarujemy ją jako prywatną, co oznacza, że można ją wywołać tylko z wnętrza klasy. Zapobiega to bezpośredniemu tworzeniu instancji klasy „Singleton” i zapewnia, że jedynym sposobem uzyskania instancji jest użycie funkcji getInstance().
Metoda getInstance() klasy „Singleton” jest zadeklarowana jako publiczna statyczna funkcja składowa. Pełni rolę ustanawiania i zapewniania dostępności instancji singleton. Wewnątrz funkcji getInstance() sprawdza, czy instancja ma wartość „nullptr”. Jeśli tak, co oznacza, że instancja jeszcze nie istnieje, używa prywatnego konstruktora do utworzenia instancji nowego obiektu klasy „Singleton”.
Funkcja showMessage() to prosta funkcja składowa, która wyświetla komunikat „Witamy z Singleton!” wiadomość. Zdefiniowano destruktor singletonu. Jest wywoływana niejawnie, gdy program kończy działanie i wyświetla komunikat „Instancja Singleton zniszczona”. komunikat wskazujący, że instancja singletonu została zniszczona. Instancja statycznej zmiennej składowej jest początkowo zdefiniowana jako „nullptr”.
Funkcja int main() rozpoczyna definicję funkcji main(). Następnie „Singleton* singletonInstance1 = Singleton::getInstance();” wywołuje funkcję getInstance() klasy „Singleton” w celu uzyskania wskaźnika do instancji singletonu. Przypisuje ten wskaźnik do zmiennej „singletonInstance1”.
Następnie „singletonInstance1->showMessage();” używa operatora strzałki (->) do wywołania funkcji showMessage() na wskaźniku „singletonInstance1”. Ta funkcja wyświetla na konsoli określony w niej komunikat. Następnie „Singleton* singletonInstance2 = Singleton::getInstance();” ponownie wywołuje funkcję getInstance(), uzyskując kolejny wskaźnik do instancji singletonu. Tym razem przypisuje wskaźnik do zmiennej „singletonInstance2”. „singletonInstance2->showMessage();” wywołuje funkcję showMessage() na wskaźniku „singletonInstance2”. Ta funkcja wyświetla komunikat „Hello from Singleton!” wiadomość ponownie do konsoli.
Na koniec „zwróć 0”; oznacza koniec funkcji main(), a program zwraca wartość 0, co oznacza pomyślne wykonanie programu.
Oto wynik objaśnionego wcześniej fragmentu kodu:
Wynik ten potwierdza, że klasa „Singleton” zapewnia utworzenie tylko jednej instancji i że dalsze wywołania funkcji getInstance() niezawodnie dają tę samą instancję.
Wniosek
Tworzenie singletonu w C++ jest bardzo użyteczną koncepcją. W tym poście początkowo omówiliśmy wprowadzenie do singletonu. Ponadto opracowano dwa przykłady implementacji singletonu w C++. Pierwsza ilustracja przedstawia implementację niecierpliwej inicjalizacji singletonu. Natomiast implementacja wzorca singletonu z leniwą inicjalizacją jest opisana w drugim przykładzie tego artykułu. Co więcej, wyświetlane są także migawki uzyskanych wyników dla odpowiednich programów.