Narzędzia użytkownika

Narzędzia witryny


singleton
/*
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;
}
singleton.txt · ostatnio zmienione: 2008/04/15 18:26 przez tsuchecki