Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Singleton a inne rozwiązania
wookieb
post
Post #1





Grupa: Moderatorzy
Postów: 8 989
Pomógł: 1550
Dołączył: 8.08.2008
Skąd: Słupsk/Gdańsk




Od ostatniego czasu zauważam wielką nagonkę na Singletona. Aż czasem głupio mi poradzić komuś w temacie by użył singletona bo zaraz pod spodem sypią sie posty typu
"Singleton ssie",
"Singleton jest dla leniwych",
"Singleton to zło" i podobne.

Osobiście nie rozumiem, dlaczego ludzie tak bardzo na to naskakują.

W swoim "frameworku" używam singletona dość często z jednego ważnego względu. Mam sporą ilość klas, których konieczne jest istnienie jednego egzemplarza.

Oto przykładowe klasy.

Site:
  • Przechowuje wszystkie ustawienia dotyczące działania systemu (znak separacjie urla i sporo takich typowo systemowych)
  • do niej importuje listę plików jakie należy dołączyć w htmlu w sekcji head
  • posiada egzemplarz klasy do obsługi URL (tworzenie, parsowanie, analiza)
  • Komunikaty dla użytkownika
  • tutaj pare innych mniej waznych funkcji
Nie widzę innego rozwiązania jak singleton. Nie wyobrazam sobie trzymania wartości klasy jako statycznych i za kazdym razem odwoływania sie do tej klasy poprzez
  1. <?php
  2. $site=new Site();
  3. ?>


Baza danych:
Tutaj chyba nie trzeba mówić, co owa klasa czyni. Rozumiem argument "A co jeżeli chcesz utworzyć połączenie z nową bazą danych?"
Można to rozwiązać bez najmniejszego problemu (np. utworzenie klasy dbConnection). Lecz w większości przypadków korzysta się z jednej bazy i jednego pola.
Singleton jak najbardziej na +;

System szablonów:
Rozszerzenie Open Power Template, gdzie dodałem singletona. Dlaczego? Bez sensu jest za każdym razem tworzenie nowego egzemplarza nawet jak chce przeparsować tylko małą część strony, niepotrzebne użycie pamięcie poprzez wartości każdego nowego egzemplarza.
Singleton + za mniejsze zużycie pamięci.

Użytkownik:
Całą gama funkcji operujących na użytkowniku, wylogowanie, logowanie, zmiana danych, zalanie herbaty, masaż i wiele innych.
Przechowuje wszystkie informacje o użytkowniku, Od jego id po preferencje, do uprawnień.
Singleton +. Jeden użytkownik jeden obiekt.

Chciałbym teraz wiedzieć jakie są argumenty osób, tak bardzo nienawidzących singletona, przemawiające za tym żeby nie używać singletona w owych sytuacjach albo wskazać inne rozwiązania które owy problem rozwiążą.

Przyznam, że nie jestem super specem od znajomości mnóstwa Wzorców Projektowych. Chętnie poznam nowe rozwiązania i pomysły które oświecą i zbeszczeszczą moje dobre zdanie o singletonie (IMG:http://forum.php.pl/style_emoticons/default/smile.gif) .

Rozwiązania które nie wchodzą w grę:
global - bron boze jak gdzies ponadpisuje egzemplarze klas
przekazywanie do kazdego obiektu wskaznika do tych klas - masochistą nie jestem aby każdy mój konstruktor składał się z bogatej listy argumentów.

Ten post edytował wookieb 8.06.2009, 07:19:26
Go to the top of the page
+Quote Post
2 Stron V   1 2 >  
Start new topic
Odpowiedzi (1 - 19)
Crozin
post
Post #2





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Cytat
Od ostatniego czasu zauważam wielką nagonkę na Singletona.
Bo z reguły poleca się go w momencie, gdy dostęp do jakiejś klasy ma być globalny (chociaż często nawet nie jest on gkobalny). A singleton powstał by zagwarantować tylko jedną instancję danej klasy.
Go to the top of the page
+Quote Post
kbsucha
post
Post #3





Grupa: Zarejestrowani
Postów: 113
Pomógł: 19
Dołączył: 2.08.2007

Ostrzeżenie: (0%)
-----


Cytat(wookieb @ 7.06.2009, 23:27:51 ) *
Od ostatniego czasu zauważam wielką nagonkę na Singletona. Aż czasem głupio mi poradzić komuś w temacie by użył singletona bo zaraz pod spodem sypią sie posty typu
"Singleton ssie",
"Singleton jest dla leniwych",
"Singleton to zło" i podobne.

Osobiście nie rozumiem, dlaczego ludzie tak bardzo na to naskakują.

W swoim "frameworku" używam singletona dość często z jednego ważnego względu. Mam sporą ilość klas, których konieczne jest istnienie jednego egzemplarza.


No dobrze, ale co z tego ze sypia posty. Przecież nikt Cię do niczego nie zmusza. Preferujesz Singletona no to czemu masz go nie stosować, ktoś inny lubi Context no to sobie go implementuje w aplikacji Jak znam życie to jeszcze wiele osób używa globali i jakoś sobie radzą, zresztą nie jedną porządną aplikacje zbudowano na globalu i jakoś świat się nie zawalił.

Ja od dłuższego czasu podchodze do tego z większym dostansem i jakoś lepiej mi się żyje (IMG:http://forum.php.pl/style_emoticons/default/guitar.gif)
Go to the top of the page
+Quote Post
LBO
post
Post #4





Grupa: Zarejestrowani
Postów: 1 415
Pomógł: 117
Dołączył: 7.09.2005
Skąd: Warszawa

Ostrzeżenie: (0%)
-----


Widzisz, tu nie chodzi do końca o to gdzie się singleton nadaje najlepiej, ale o to co ze sobą niesie.

Do wad zaliczam:
1. Testowanie singletona to masakra.
2. Singleton ukrywa zależności pomiędzy obiektami (nie są to puste słowa, stoi to później na przeszkodzie w rozwijaniu aplikacji)
3. Dziedziczenie, a singleton.... wolne żarty.
Go to the top of the page
+Quote Post
wookieb
post
Post #5





Grupa: Moderatorzy
Postów: 8 989
Pomógł: 1550
Dołączył: 8.08.2008
Skąd: Słupsk/Gdańsk




Cytat(kbsucha @ 7.06.2009, 23:46:31 ) *
No dobrze, ale co z tego ze sypia posty. Przecież nikt Cię do niczego nie zmusza. Preferujesz Singletona no to czemu masz go nie stosować, ktoś inny lubi Context...

Dlatego pytałem się o propozycje lepszych rozwiązań moich przykładowych zagadnień.
Go to the top of the page
+Quote Post
dr_bonzo
post
Post #6





Grupa: Przyjaciele php.pl
Postów: 5 724
Pomógł: 259
Dołączył: 13.04.2004
Skąd: N/A

Ostrzeżenie: (0%)
-----


Cytat(LBO @ 8.06.2009, 00:13:31 ) *
Widzisz, tu nie chodzi do końca o to gdzie się singleton nadaje najlepiej, ale o to co ze sobą niesie.

Do wad zaliczam:
1. Testowanie singletona to masakra.
2. Singleton ukrywa zależności pomiędzy obiektami (nie są to puste słowa, stoi to później na przeszkodzie w rozwijaniu aplikacji)
3. Dziedziczenie, a singleton.... wolne żarty.


@LBO: to prosze, pokaz jak rozwiazujesz problem modelu (przyklad uzycia), ktory korzysta z bazy danych.
Go to the top of the page
+Quote Post
erix
post
Post #7





Grupa: Moderatorzy
Postów: 15 467
Pomógł: 1451
Dołączył: 25.04.2005
Skąd: Szczebrzeszyn/Rzeszów




Cytat
przekazywanie do kazdego obiektu wskaznika do tych klas - masochistą nie jestem aby każdy mój konstruktor składał się z bogatej listy argumentów.

Zawsze zostaje func_get_args" title="Zobacz w manualu PHP" target="_manual... Ale to nie zmienia faktu, że trzeba uwzględnić jakąś warstwę pobierającą uchwyt.

Ja byłbym za jednym obiektem "rdzenia" z poszczególnymi modułami ukrytymi wewnątrz. A rdzeń można albo przekazać jako zmienną w parametrze, albo jako własność klasy (jeśli chodzi o model; konstruktor modelu tworzy instancję z ustawionym wskaźnikiem rdzenia).

Nie mam też nic przeciwko Singletonowi, jeśli jest stosowany z głową; nie popadajmy w paranoję, że forma ważniejsza od treści, albo tylko dlatego, że jest to sposób na obejście global." title="Zobacz w manualu PHP" target="_manual. Po to jest rozum, żeby rozgraniczyć. ;]
Go to the top of the page
+Quote Post
LBO
post
Post #8





Grupa: Zarejestrowani
Postów: 1 415
Pomógł: 117
Dołączył: 7.09.2005
Skąd: Warszawa

Ostrzeżenie: (0%)
-----


Cytat
@LBO: to prosze, pokaz jak rozwiazujesz problem modelu (przyklad uzycia), ktory korzysta z bazy danych.


Mam fabrykę modeli w której wstrzykuje kontekst.

[nowy post]

Cytat(wookieb @ 7.06.2009, 23:27:51 ) *
przekazywanie do kazdego obiektu wskaznika do tych klas - masochistą nie jestem aby każdy mój konstruktor składał się z bogatej listy argumentów.


Wstrzykiwanie nie odbywa się tylko poprzez konstruktor, czasami wystarczą tylko settery. Poczytaj o kontenerach IoC np w Springu.

Ten post edytował LBO 8.06.2009, 08:11:18
Go to the top of the page
+Quote Post
mike
post
Post #9





Grupa: Przyjaciele php.pl
Postów: 7 494
Pomógł: 302
Dołączył: 31.03.2004

Ostrzeżenie: (0%)
-----


Ja chciałbym się przyłączyć do ~LBO żeby nie wyszło że prowadzi samotną krucjatę.
Uwierzcie, że istnieją inne, dużo lepsze sposoby na rozwiązywanie wspomnianych problemów.

Odwrócenie sterowania (IoC) za pomocą wstrzykiwania zależności (ang. Dependency Injection, DI) jest dużo lepszym rozwiązaniem i wcale nie opiera się na globalnych obiektach tworzonych za pomocą Singletona.
Zapraszam do lektury: Inversion of Control Containers and the Dependency Injection pattern autorstwa Martina Fowlera

Poza tym nikt nie odniósł się do wad wspomnianych przez ~LBO. W światku "script kids by PHP" testowanie i projektowanie to też poważne problemy i zagadnienia.

P.S.
~LBO Twoja sygnaturka mnie powaliła. Git.
Go to the top of the page
+Quote Post
starach
post
Post #10





Grupa: Zarejestrowani
Postów: 999
Pomógł: 30
Dołączył: 14.01.2007
Skąd: wiesz ?

Ostrzeżenie: (0%)
-----


A co w takim razie z menadżerem bazy danych. Skoro klasy Peer są statyczne ( czy to Propel czy nawet mój miniORM ) to jak mam wywoływać DatabaseManager, która to metoda instance() pobiera z konfiguracji odpowiednie ustawienia bazy i zwraca już połączony sterownik. Chyba mniej więcej działa tak Doctrine.

Generalnie to niby nie jest singleton tylko factory, tylko że zasada działania pozostaje bardzo zbliżona do pierwszego.
Go to the top of the page
+Quote Post
wookieb
post
Post #11





Grupa: Moderatorzy
Postów: 8 989
Pomógł: 1550
Dołączył: 8.08.2008
Skąd: Słupsk/Gdańsk




Strasznie nie podoba mi się wstrzykiwanie wskaźników do klas z tego wzgledu, ze jest to bardzo niewygodne.
A juz organizacja wstrzykiwan przez xmle (o ile dobrze zrozumiałem "na szybko") jest głupotą.

Problem rozwiązałem w trochę inny sposób. Mianowicie statyczna klasa
  1. <?php
  2. /**
  3. *    Statyczna klasa służąca jako obejście dla singletona. Przechowuje egzemplarze klas, których potrzebny jest tylko jeden egzemplarz.
  4. *    @author Wookieb
  5. *    @version 1.0
  6. *    @package Utils
  7. */
  8.  
  9. class GlobalHandler
  10. {
  11.    /**
  12.     *    Przechowuje egzemplarze klas
  13.     *    @var array
  14.     */
  15.    private static $instances=array();
  16.    
  17.    /**
  18.     *    Zapisuje do przechowania
  19.     *    @param string $name alias pod jakim zapisac dane
  20.     *    @param mixed $var dane do przechowania
  21.     */
  22.    public static function register($name, $var)
  23.    {
  24.        self::$instances[$name]=$var;
  25.    }
  26.    /**
  27.     *    Usuwa przechowane dane o podanej nazwie
  28.     *    @param string $name alias danych
  29.     *    @return bool true jezeli taki alias istnieje, false jezeli nie
  30.     */
  31.    public static function unregister($name)
  32.    {
  33.        if(isset(self::$instances[$name]))
  34.        {
  35.            unset(self::$instances[$name]);
  36.            return true;
  37.        }
  38.        else return false;
  39.    }
  40.    /**
  41.     *    Zwraca dane o podanym aliasie
  42.     *    @param string $name alias danych
  43.     *    @return mixed
  44.     */
  45.    public static function get($name)
  46.    {
  47.        if(isset(self::$instances[$name]))
  48.        {
  49.            return self::$instances[$name];
  50.        }
  51.        else return false;
  52.    }
  53.    
  54.    /**
  55.     *    Usuwa wszystkie przechowane dane
  56.     */
  57.    public static function unregisterAll()
  58.    {
  59.        self::$instances=array();
  60.    }
  61. }
  62. ?>

Sądze ze działanie jest na tyle jasne, że niczego nie trzeba tłumaczyć.

Musiałem wywalić wszystkie singletony z tego względu, że będę chciał czasem symulować stronę w stronie (oczywiście nie za pomocą iframe).

Problem różnych połączeń z bazą danych rozwiązałem w ten sposób iż utworzyłem klasę DbConnection która realizuje połączenie. Egzemplarz owej klasy przekazuje do głównej klasy zarządzającej zapytaniami (Db). W razie potrzeby połączenia z inną bazą, po prostu tworze nowy egzemplarz DbConnection i na jakiś czas zamieniam w Db. Działa bardzo sprawnie i wydajnie.

Dzięki wszystkim za sugestie (IMG:http://forum.php.pl/style_emoticons/default/smile.gif)

Ten post edytował wookieb 11.06.2009, 21:48:26
Go to the top of the page
+Quote Post
LBO
post
Post #12





Grupa: Zarejestrowani
Postów: 1 415
Pomógł: 117
Dołączył: 7.09.2005
Skąd: Warszawa

Ostrzeżenie: (0%)
-----


Cytat(mike @ 8.06.2009, 10:13:44 ) *
Ja chciałbym się przyłączyć do ~LBO żeby nie wyszło że prowadzi samotną krucjatę

@mike, dzięki wielkie za wsparcie - jak zwykle, z Twojej strony, trafnie i konkretnie. Naprawdę bardzo doceniam.

Cytat(mike @ 8.06.2009, 10:13:44 ) *
P.S.
~LBO Twoja sygnaturka mnie powaliła. Git.

(IMG:http://forum.php.pl/style_emoticons/default/tongue.gif) Starałem się

Cytat(wookieb @ 11.06.2009, 22:37:59 ) *
Strasznie nie podoba mi się wstrzykiwanie wskaźników do klas z tego wzgledu, ze jest to bardzo niewygodne.
A juz organizacja wstrzykiwan przez xmle (o ile dobrze zrozumiałem "na szybko") jest głupotą.

Głupotą? A możesz poprzeć to jakimiś argumentami?

Bo ja dzięki tej głupocie, osiągam tyle samo co przy użyciu Singletona, ale bez jego przykrych naleciałości.

Co do twojego rozwiązania. Wiele to od Singletona nie odbiega. Teraz masz Rejestr w czystej jego postaci - drugi, zaraz po Singletonie, niezbyt ciekawy pod względem inżynieryjnym wzorzec.
Na blogu Federico Cargneluttiego - bardzo cenię sobie tego autora, mnóstwo ciekawych artykułów m.in. o wzorcach - znajdziesz kilka słów na ten temat.

Mam ogromną nadzieję, że po wydaniu Symfony 2.0 wraz z autorskim kontenerem IoC programiści zaczną wnikliwiej przyglądać się pewnym problemom.

Pozdrawiam, Alan

Ten post edytował LBO 11.06.2009, 23:04:35
Go to the top of the page
+Quote Post
wookieb
post
Post #13





Grupa: Moderatorzy
Postów: 8 989
Pomógł: 1550
Dołączył: 8.08.2008
Skąd: Słupsk/Gdańsk




Cytat(LBO @ 11.06.2009, 23:51:30 ) *
Głupotą? A możesz poprzeć to jakimiś argumentami?

Nie wyobrażam sobie aby przy tworzeniu instancji obiektu musiała sobie parsować xml-a, żeby działała. Strata czasu procesora.
Cytat
Bo ja dzięki tej głupocie, osiągam tyle samo co przy użyciu Singletona, ale bez jego przykrych naleciałości.

No widzisz. Ja rozwiązałem w swój sposób. Idealny do mojego rozwiązania. W razie potrzeby usuwam wszystkie przechowane dane i wrzucam drugie. Rozwiązanie szybkie, wydajne, nie marnujące pamięci.

Cytat
Co do twojego rozwiązania. Wiele to od Singletona nie odbiega. Teraz masz Rejestr w czystej jego postaci - drugi, zaraz po Singletonie, niezbyt ciekawy pod względem inżynieryjnym wzorzec.
Na blogu Federico Cargneluttiego - bardzo cenię sobie tego autora, mnóstwo ciekawych artykułów m.in. o wzorcach - znajdziesz kilka słów na ten temat.

Twoje zdanie, nie tępie.


Każde rozwiązanie ma swoje wady i zalety. Ja potrzebowałem łatwego, szybkiego sposobu do uzyskiwania dostepu do egzemplarza klasy bez singletona. Rozwiązało to mój problem i dla mnie jest to koniec tematu.

Ten post edytował wookieb 12.06.2009, 08:50:59
Go to the top of the page
+Quote Post
LBO
post
Post #14





Grupa: Zarejestrowani
Postów: 1 415
Pomógł: 117
Dołączył: 7.09.2005
Skąd: Warszawa

Ostrzeżenie: (0%)
-----


Cytat(wookieb @ 12.06.2009, 09:31:39 ) *
Nie wyobrażam sobie aby przy tworzeniu instancji obiektu musiała sobie parsować xml-a, żeby działała. Strata czasu procesora.


W dobrych kontenerach, konfiguracja parsowana jest tylko raz i kompilowana do czystego PHP. Narzutu więc nie ma, bo suma sumarum taki kontener generuje to samo, co ty byś napisał z palca (w pewnym stopniu abstrakcji ofkorz).

Cytat(wookieb @ 12.06.2009, 09:31:39 ) *
No widzisz. Ja rozwiązałem w swój sposób. Idealny do mojego rozwiązania. W razie potrzeby usuwam wszystkie przechowane dane i wrzucam drugie. Rozwiązanie szybkie, wydajne, nie marnujące pamięci.


Nie marnujące pamięci? W rejestrze trzymasz cały zestaw zainstancjonowanych obiektów i jest tak nawet, gdy nie używasz połowy z Nich. Kontenery, dzięki konfiguracji, są zdolne tworzyć obiekty dopiero na żądanie.
Go to the top of the page
+Quote Post
wookieb
post
Post #15





Grupa: Moderatorzy
Postów: 8 989
Pomógł: 1550
Dołączył: 8.08.2008
Skąd: Słupsk/Gdańsk




Mylisz się. Wrzucam tylko te które używam i których konieczne jest istnienie chociaż jednego egzemplarza. Nie sprawdzisz tego więc nie możesz z góry zakładać, że ich nie używam.

Ten post edytował wookieb 12.06.2009, 10:22:29
Go to the top of the page
+Quote Post
rzymek01
post
Post #16





Grupa: Zarejestrowani
Postów: 592
Pomógł: 62
Dołączył: 3.08.2006

Ostrzeżenie: (0%)
-----


Ze swojej strony chciałbym się dowiedzieć w jaki sposób zastąpić Singletona (czy trzeba?) w realizacji swoistego controllera (przetwarza eventy i wywołuje odpowiednie moduły) który musi mieć tylko 1 instancję?

Pozdrawiam

Ten post edytował rzymek01 12.06.2009, 11:31:02
Go to the top of the page
+Quote Post
Fifi209
post
Post #17





Grupa: Zarejestrowani
Postów: 4 655
Pomógł: 556
Dołączył: 17.03.2009
Skąd: Katowice

Ostrzeżenie: (0%)
-----


@up
Ta klasa rejestruje zmienne, usuwasz singletona w swojej klasie. W tej rejestrujesz obiekt i gotowe. (IMG:http://forum.php.pl/style_emoticons/default/haha.gif)

@edit

  1. <?php
  2. public static function get($name)
  3.   {
  4.       if(isset(self::$instances[$name]))
  5.       {
  6.           return self::$instances[$name];
  7.       }
  8.       else return false;
  9.   }
  10. ?>


A czemu tak? (IMG:http://forum.php.pl/style_emoticons/default/biggrin.gif) Nie lepiej użyć "magicznych" metod php 5?
__get()

P.S. Ta klasa może służyć też do przechowywania zwykłych zmiennych - np. zamiast używania global.

Ten post edytował fifi209 12.06.2009, 12:17:03
Go to the top of the page
+Quote Post
wookieb
post
Post #18





Grupa: Moderatorzy
Postów: 8 989
Pomógł: 1550
Dołączył: 8.08.2008
Skąd: Słupsk/Gdańsk




Cytat(fifi209 @ 12.06.2009, 12:39:36 ) *
A czemu tak? (IMG:http://forum.php.pl/style_emoticons/default/biggrin.gif) Nie lepiej użyć "magicznych" metod php 5? __get()

Nie bo tak jest znacznie prosciej

Cytat(fifi209 @ 12.06.2009, 12:39:36 ) *
P.S. Ta klasa może służyć też do przechowywania zwykłych zmiennych - np. zamiast używania global.

Nikt nie powiedział, że to ma być wyłącznie do obiektów.
Go to the top of the page
+Quote Post
Fifi209
post
Post #19





Grupa: Zarejestrowani
Postów: 4 655
Pomógł: 556
Dołączył: 17.03.2009
Skąd: Katowice

Ostrzeżenie: (0%)
-----


Cytat(wookieb @ 12.06.2009, 13:20:31 ) *
Nie bo tak jest znacznie prosciej

Czemu uważasz, że jest prościej? Zawsze to kilka znaków mniej do wyklikania.

Cytat(wookieb @ 12.06.2009, 13:20:31 ) *
Nikt nie powiedział, że to ma być wyłącznie do obiektów.


Jak nie? (IMG:http://forum.php.pl/style_emoticons/default/biggrin.gif)
Cytat
Statyczna klasa służąca jako obejście dla singletona. Przechowuje egzemplarze klas, których potrzebny jest tylko jeden egzemplarz
Go to the top of the page
+Quote Post
wookieb
post
Post #20





Grupa: Moderatorzy
Postów: 8 989
Pomógł: 1550
Dołączył: 8.08.2008
Skąd: Słupsk/Gdańsk




Cytat(fifi209 @ 12.06.2009, 13:23:07 ) *
Czemu uważasz, że jest prościej? Zawsze to kilka znaków mniej do wyklikania.

Bo __get chyba nie działa na statycznych właściwościach


Cytat(fifi209 @ 12.06.2009, 13:23:07 ) *


A widzisz tam synonim słowa "wyłącznie"?

Ten post edytował wookieb 12.06.2009, 12:29:49
Go to the top of the page
+Quote Post

2 Stron V   1 2 >
Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 28.09.2025 - 06:00