Dyskusja:Singleton (wzorzec projektowy)

message: * Poprawny/średnie - artykuł można dalej rozbudowywać, ale ogólnie wygląda przyzwoicie. --Zyx (dyskusja) 14:07, 20 wrz 2010 (CEST)
thread_title:  Ocena jakości 

message: Takie teksty:
replies: text: //tak w ogole w jezyku z bezposrednim dostepem do pamieci singleton to bajka
są nie na miejscu. To jest encyklopedia. Tu się podaje informacje, a nie lansuje swoje ulubione języki [kolega lubi managed jak sądzę].
Podany przykład rzeczywiście nie jest doskonały, bo np. umożliwia wywołanie delete na pozyskanym wskaźniku i pozwala na zepsucie całego mechanizmu [zwolnienie instancji zamkniętej wnętrzu klasy], jednak nie jest to wina "języka z bezpośrednim dostępem do pamięci", lecz wina niepoprawnego przykładu [mam nadzieję że to nie było celowe]. Przecież wyraźnie pisze w definicji wzorca Singleton, że:

text: "i następnie zwraca ją przez referencję."
Więc skąd tu wskaźniki? :P To one są przyczyną problemów, a nie "język z bezpośrednim dostępem do pamięci". Wystarczy zamienić ten kod na np. taki:
===Kod w języku C++===
 //Definicja
 class singleton
 {
  private:
        static singleton instance;
        singleton();
        singleton(const singleton &);
        singleton& operator=(const singleton&);
  public:
        string method() { return "singleton pattern"; }
        ~singleton();
        static singleton& getInstance()
        {
          return instance;
        }
 };
 
 //Inicjalizacja statycznego składnika.
 //Wywoła konstruktor [w końcu klasa ma dostęp do własnej prywaty].
 singleton singleton::instance;
 
 //Uzycie
 std::cout << singleton::getInstance().method();
Ewentualnie jeśli chcemy mieć większą kontrolę nad momentem utworzenia instancji singletonu, można to zapisać też tak:
===Kod w języku C++===
 //Definicja
 class singleton
 {
  private:
        singleton();
        singleton(const singleton &);
        singleton& operator=(const singleton&);
  public:
        string method() { return "singleton pattern"; }
        ~singleton();
        static singleton& getInstance()
        {
          //Inicjalizacja statycznego obiektu.
          //Obiekt zostanie utworzony przy pierwszym wywołaniu tej metody
          //i tylko wtedy nastąpi inicjalizacja przy pomocy konstruktora.
          //Każde następne wywołanie jedynie zwróci referencję tego obiektu.
          static singleton instance;
          return instance;
        }
 };
Jest to tzw. sposób Meyersa i został opisany w jego książce "More Effective C++".
No cóż.. ale czego można się spodziewać po koderze [autorze tego kodu na Wikipedii], który nie zna nawet dobrze składni C++ i myśli, że trzeba dawać średniki po każdej zamykającej klamrze ;P
-- SasQ
Moim zdaniem używanie wskażnika jest wygodniejsze, przynajmniej dla mnie. Problem
z operatorem delete() mozna rozwiązać przesuwając destruktor do sekcji prywatnej,
używam GCC gdzie to dziala.
-- Wieczyk
thread_title:  Przykład w C++ 

message: //Definicja
 class singleton
 {
  private:
        static singleton instance;
        singleton();
        singleton(const singleton &);
        singleton& operator=(const singleton&);
  public:
        string method() { return "singleton pattern"; }
        ~singleton();
        static singleton& getInstance()
        {
          return instance;
        }
 };
 
 //Inicjalizacja statycznego składnika.
 //Wywoła konstruktor [w końcu klasa ma dostęp do własnej prywaty].
 singleton singleton::instance;
 
 //Uzycie
 std::cout << singleton::getInstance().method();
Ewentualnie jeśli chcemy mieć większą kontrolę nad momentem utworzenia instancji singletonu, można to zapisać też tak:
thread_title: Kod w języku C++

message: //Definicja
 class singleton
 {
  private:
        singleton();
        singleton(const singleton &);
        singleton& operator=(const singleton&);
  public:
        string method() { return "singleton pattern"; }
        ~singleton();
        static singleton& getInstance()
        {
          //Inicjalizacja statycznego obiektu.
          //Obiekt zostanie utworzony przy pierwszym wywołaniu tej metody
          //i tylko wtedy nastąpi inicjalizacja przy pomocy konstruktora.
          //Każde następne wywołanie jedynie zwróci referencję tego obiektu.
          static singleton instance;
          return instance;
        }
 };
Jest to tzw. sposób Meyersa i został opisany w jego książce "More Effective C++".
No cóż.. ale czego można się spodziewać po koderze [autorze tego kodu na Wikipedii], który nie zna nawet dobrze składni C++ i myśli, że trzeba dawać średniki po każdej zamykającej klamrze ;P
-- SasQ
Moim zdaniem używanie wskażnika jest wygodniejsze, przynajmniej dla mnie. Problem
z operatorem delete() mozna rozwiązać przesuwając destruktor do sekcji prywatnej,
używam GCC gdzie to dziala.
-- Wieczyk
thread_title: Kod w języku C++

message: Widać, że C++ jest bardzo kontrowersyjnym językiem jesli chodzi o implementację wzorca singletonu. Zatem dorzucę się z kolejną propozycją kodu wartą rozważenia zamieszczenia na stronie artykułu.
 class Singleton
 {
 public:
    static Singleton* getInstance()
    {
        if (!pInstance)
            pInstance = new Singleton;
        return pInstance;
    }
    std::string sayHello()
    {
        return "Hello, I'm Singleton!";
    }
 private:
    static Singleton* pInstance;
    Singleton() {}
    Singleton(const Singleton&) {}
 };
Jawne zainicjowanie
 Singleton* Singleton::pInstance = 0;
Gdzieś dalej
 std::cout << Singleton::getInstance->sayHello() << std::endl;
Zaletą przedstawionego podejści jest ukrycie wewnątrz klasy wywołania konstruktora, który zostanie wykonany tylko przy pierwszym odwołaniu do obiektu.
replies: text: Oba z podanych przeze mnie przykładów ukrywają konstruktor wewnątrz klasy [private]. A jeśli chodziło ci o to, że tylko przy pierwszym wywołaniu getInstance() zostanie wywołany konstruktor, to w moim drugim przykładzie kodu też tak jest - konstruktor zainicjalizuje obiekt statyczny wewnątrz getInstance() tylko przy jej pierwszym wywołaniu. Przy następnych będzie go już tytlko zwracał. --SasQ
Ponad to inicjowanie obiektu statycznego jest dokonywane przez kompilator w trakcie tłumaczenia programu a w poprzednio zamieszczonych fragmentach kodu składowa reprezentująca instancję była inicjowana dopiero podczas wykonania programu.

text: Twoje rozwiązanie ma aż dwie poważne wady:

text: 1. Instancja singletonu jest zwracana znów przez wskaźnik, co może kusić użytkownika do wywołania na nim delete i zniszczenia skrywanego obiektu [do którego przecież nie powinien mieć dostępu].

text: 2. Zastanów się, gdzie będzie wołane delete na twoim singletonie? Odpowiedź brzmi: nigdzie :P Obiekt będący wskaźnikiem na ten singleton zostanie usunięty gdy program się zakończy, ale już właściwy obiekt singletona utworzony na stercie operatorem new nie, bo nigdzie go nie deletujesz. Co prawda pamięć przydzielona na stercie jest w większości systemów operacyjnych [choć nie wszystkich!] zwalniana po zakończeniu programu, to już np. inne zasoby mogą pozostać niezwolnione [np. otwarte pliki, nawiązane połączenia sieciowe itp.]. Jest to poważna wpadka, bo powoduje wycieki zasobów!

text: Dlatego skłaniałbym się raczej ku rozwiązaniu 2 [Meyersa], bo jest najlepsze jakie dotąd widziałem.

text: --SasQ

text: Po dalszym zapoznawaniu się z zagadnieniem Singletonów przyznaję, że podany przeze mnie przykład był obarczony wskazanymi błędami. Natomiast skoro wyżej w dyskusji pojawiły się już lepsze rozwiązania (a przynajmniej o niebo lepsze niż w artykule) proponuję ten okropny przykład z artykułu zamienić na jeden z powyższych. Doskonałego prawdopodobnie się nie znajdzie.
Pozdrawiam Webprog 01:33, 12 lut 2007 (CET)
thread_title:  Przykład w C++ po raz kolejny 

message: podany sposob jest nieoptymlany poniewaz KAZDY dostep do instancji jest sychchronizowany, a co za tym idzie niesie spory narzut.
bardziej wydajnie jest sprawdzac czy isteje podejrzenie, ze instacja nie jest jeszcze utworzona, a nastepnie w spob synchronizowany sie o tym upewnic:
public class Singleton {
    private static Singleton instance = null;
    public static Singleton getInstance() {
        if (instance == null){
           synchronized(Singleton.class){
               if (instance == null){
                   instance = new Singleton();
               }            
           }
        }
        return instance;
    } 
    // Deklaracja prywatnego konstruktora - zastępuje domyślny konstruktor publiczny
    private Singleton() {}
}
Sławomir Sobótka
thread_title:  Implementacja w Javie 

message: Dlaczego implementacja singletonu w C++ ma przedefiniowany publiczny destruktor? Domyślnie generowany ma dokładnie taką samą sygnaturę i również nic nie robi. Zwykła pomyłka, miał być prywatny czy celowe działanie? Czekam narazie na odpowiedź, za jakieś 2 tygodnie bez odpowiedzi poprawię (czekam, bo możliwe, że to ja czegoś nie dostrzegam).
--217.153.99.181 (dyskusja) 00:14, 25 gru 2008 (CET)
Co też robię. Podejrzewam, że ktoś odruchowo "doimplementował" do wersji Meyersa destruktor wewnątrz klasy, chociaż po tej poprawce kod stracił sens.
--217.153.99.179 (dyskusja) 03:03, 27 sty 2009 (CET)
thread_title:  Przykład C++: publiczny destruktor