Różnice między wybraną wersją a wersją aktualną.
— |
singleton [2008/04/15 18:26] (aktualna) tsuchecki utworzono |
||
---|---|---|---|
Linia 1: | Linia 1: | ||
+ | <code cpp> | ||
+ | /* | ||
+ | Autor: Tadeusz Suchecki | ||
+ | Wzorzec: Singleton | ||
+ | |||
+ | Zastosowanie: Singleton to wzorzec konstrukcyjny przeznaczony do ograniczania | ||
+ | mozliwosci tworzenia obiektow danej klasy do pojedynczej instancji. Ponadto | ||
+ | musi zapewniac globalny dostep do istniejacej instancji obiektu. | ||
+ | Czesto w aplikacji istnieje potrzeba stworzenia klasy, ktora posiadalaby | ||
+ | wylacznie jedna instancje. Zwykle zwiazane to jest z zapewnieniem wiekszej | ||
+ | wydajnosci aplikacji, np. przy dostepie do bazy danych, gdzie kazde laczenie | ||
+ | sie z baza jest dla aplikacji kosztowne, bo wymaga czasochlonnego | ||
+ | uwierzytelnienia i autoryzacji. W tym przypadku sensowniej jest stworzyc jeden | ||
+ | obiekt przechowujacy sesje polaczenia i wykorzystac go do przeslania wielu | ||
+ | zapytan. Rowniez w mniej krytycznych przypadkach korzystne jest stosowanie | ||
+ | wzorca singletonu. Wskazowka do jego uzycia jest sytuacja, gdy potrzebna jest | ||
+ | wylacznie jedna instancja obiektu, ktora wywoluje wiele roznych czesci | ||
+ | aplikacji. W takich przypadkach tworzenie obiektu, a nastepnie niszczenie | ||
+ | go jest marnotrawstwem zasobow pamieci. | ||
+ | |||
+ | Opis: Wzorzec singletonu implementuje sie przez stworzenie klasy, ktora posiada | ||
+ | statyczna metode, ktora najpierw sprawdza, czy istnieje juz instancja tej klasy | ||
+ | - jesli nie istnieje to tworzy ja - i nastepnie zwraca ja przez referencje. | ||
+ | Instancja klasy jest przechowywana w prywatnym lub chronionym, statycznym polu, | ||
+ | do ktorego dostep ma tylko opisana wyzej metoda. Owa metoda dostepowa jest | ||
+ | jedyna droga pozyskania instancji obiektu singletonu - aby uniemozliwic | ||
+ | tworzenie dodatkowych instancji w zwykly sposob, czyli przez wywolanie | ||
+ | konstruktora, deklaruje sie go jako prywatny lub chroniony. | ||
+ | Dodatkowa korzyscia z zastosowania takiego rozwiazania jest to, ze caly proces | ||
+ | jest niewidoczny dla uzytkownika i nie musi on wiedziec, czy instancja istnieje | ||
+ | czy tez nie. | ||
+ | */ | ||
+ | |||
+ | /* | ||
+ | Dobrym przykladem na zastosowanie singletonu jest polaczenie do bazy danych. | ||
+ | W przykladzie nie bede zaglebial sie w samo polaczenie i ogranicze do wypisania | ||
+ | informacji o id klienta i numerze wywolania. Informacje te powinny pozwolic | ||
+ | zauwazyc sposob dzialania obiektu. | ||
+ | */ | ||
+ | |||
+ | #include <pthread.h> | ||
+ | #include <memory> | ||
+ | #include <iostream> | ||
+ | #include <string> | ||
+ | #include <sstream> | ||
+ | |||
+ | /* | ||
+ | Mutex potrzebny do synchronizacji wielu watkow | ||
+ | */ | ||
+ | class Mutex | ||
+ | { | ||
+ | public: | ||
+ | Mutex() | ||
+ | { pthread_mutex_init(&m, 0); } | ||
+ | |||
+ | void lock() | ||
+ | { pthread_mutex_lock(&m); } | ||
+ | |||
+ | void unlock() | ||
+ | { pthread_mutex_unlock(&m); } | ||
+ | |||
+ | private: | ||
+ | pthread_mutex_t m; | ||
+ | }; | ||
+ | /* | ||
+ | Pomocniczy locker dla wygody | ||
+ | */ | ||
+ | class MutexLocker | ||
+ | { | ||
+ | public: | ||
+ | MutexLocker(Mutex& pm): m(pm) { m.lock(); } | ||
+ | ~MutexLocker() { m.unlock(); } | ||
+ | private: | ||
+ | Mutex& m; | ||
+ | }; | ||
+ | /* | ||
+ | Singleton - polaczenie do bazy danych ktore w tym programie moze byc tylko | ||
+ | jedno. Gdy jest potrzebne a nie istnieje jest tworzone gdy istnieje zwracana | ||
+ | jest referencja na istniejace. Po wywolaniu GetData(id) zwraca informacje o | ||
+ | numerze wywolania i id klienta wywolujacego. | ||
+ | */ | ||
+ | class DB_Connection | ||
+ | { | ||
+ | public: | ||
+ | static DB_Connection& Instance(); | ||
+ | int example_data; | ||
+ | ~DB_Connection() { } | ||
+ | std::string GetData(int id); | ||
+ | |||
+ | protected: | ||
+ | DB_Connection(): example_data(1) {} | ||
+ | /* | ||
+ | chroniony aby nie dalo sie stworzyc instancji inaczje niz przez Instance(); | ||
+ | */ | ||
+ | |||
+ | private: | ||
+ | static std::auto_ptr<DB_Connection> theSingleInstance; | ||
+ | static Mutex m; | ||
+ | }; | ||
+ | /* | ||
+ | Chyba nie wymaga komentarza | ||
+ | */ | ||
+ | std::string DB_Connection::GetData(int id) | ||
+ | { | ||
+ | std::ostringstream os; | ||
+ | os<<"odwolanie nr: "<<example_data++<<" poczynione przez urzytkownika o id "<<id; | ||
+ | return os.str(); | ||
+ | } | ||
+ | /* | ||
+ | Zapewnienie istnienia jednej instancji. | ||
+ | Jesli instancja nie istnieje jest tworzona. | ||
+ | Zwracana jest referencja na instancje. | ||
+ | */ | ||
+ | DB_Connection& DB_Connection::Instance() | ||
+ | { | ||
+ | if (theSingleInstance.get() == 0) | ||
+ | { | ||
+ | MutexLocker obtain_lock(m); | ||
+ | if (theSingleInstance.get() == 0) | ||
+ | { | ||
+ | theSingleInstance.reset(new DB_Connection); | ||
+ | } | ||
+ | } | ||
+ | return *theSingleInstance; | ||
+ | } | ||
+ | |||
+ | std::auto_ptr<DB_Connection> DB_Connection::theSingleInstance; | ||
+ | |||
+ | Mutex DB_Connection::m; | ||
+ | |||
+ | /* | ||
+ | Procedura testowa: | ||
+ | kolejno klienci 1,2,3 wywoluja baze | ||
+ | */ | ||
+ | int main() | ||
+ | { | ||
+ | std::cout << DB_Connection::Instance().GetData(1) << std::endl; | ||
+ | std::cout << DB_Connection::Instance().GetData(2) << std::endl; | ||
+ | std::cout << DB_Connection::Instance().GetData(3) << std::endl; | ||
+ | std::cout << DB_Connection::Instance().GetData(1) << std::endl; | ||
+ | std::cout << DB_Connection::Instance().GetData(2) << std::endl; | ||
+ | std::cout << DB_Connection::Instance().GetData(3) << std::endl; | ||
+ | std::cout << DB_Connection::Instance().GetData(1) << std::endl; | ||
+ | std::cout << DB_Connection::Instance().GetData(2) << std::endl; | ||
+ | std::cout << DB_Connection::Instance().GetData(3) << std::endl; | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | </code> |