Krytyka Singletona

0

Googlujac znalazlem kilka argumentow, jeden z nich to to, ze obiekt Singletonu jest globalnie dostepny co lamie jakies tam zasady OOP, ale czym to sie rozni od tego, ze definicja klasy tez jest przeciez globalnie dostepna (zmienia sie jedynie moment w ktorym uzyskujemy obiekt), przez co mozemy zrobic:

//gdzies tam mamy klase powiedzmy Database ktora mniej wiecej wiadomo do czego moze nam sluzyc
JakasKlasa::metoda()
{
  Database * db;
  //db = new Database;
  //db = Database::getSingleton();
  //cos tam robimy z db
}

bez wzgledu na to czy Database jest Singletonem czy nie to i tak mamy do niej dostep.

Gdzies na jakims blogu przeczytalem, ze trudniej sie testuje klase ktora odwoluje sie do Singletonu z powodu takiego, ze klasy nie mozna se wydziabac do nowego projektu bo "potrzebny jest tez ten Singleton", a czy jak bede przekazywal taki obiekt np w parametrach to definicja klasy nie bedzie mi potrzebna?

Paradoksalnie jedynym sensownym argumentem jaki gdzies tam znalazlem to takie prymitywne zdanie: "korzystajac z Singletonu obiekt bierze sie z powietrza", no i rzeczywiscie, cos w tym jest, wydaje mi sie, ze "dobry" projekt OOP mozna przedstawic w postaci drzewa (czy tam UMLa - niestety nie znam sie), to dziedziczy po tym, to zawiera w polu to i tamto a tu nagle odwolanie do jakiegos obiektu nie wiadomo skad. Ale jak sie zastanowic to kazda klasa ktorej obiekt robimy sobie np w jakiejs funkcji (np std::string) tez sie bierze z nikad.

Od razu prosze o nienaskakiwanie na mnie za cienka argumentacje bo na razie jestem neutralny i temat zalozylem po to zeby wysluchac argumentacji niezaleznych osob po czym mam nadzieje wyrobie sobie jakies zdanie na ten temat.

Ah, no i tak wiem, ze istnieja w sieci rozne publikacje na ten temat ale mi zalezy na dyskusji (czyli na wymianie i ew obalaniu przez innych argumentow) wsrod osob ktore jakos tam znam (czyli Was).

0

Singleton jako wzorzec wypadł z łask w momencie gdy powstały frameworki typu Spring czy PicoContainer. Do wad singletonu należy trudna rozszerzalność (prywatny konstruktor) i stosunkowo mała przenośność.
Pytanie:
Co się stanie gdy potrzebujesz dostępu do kilku baz danych, a "sterownik" jest singletonem?
Oczywiście polegniesz, albo będziesz przepisywał "sterownik".

Dlatego też wymyślono inne podejście niech wszędzie tam gdzie potrzebny jest dany obiekt będzie możliwość pobrania implementacji z fabryki (publiczny jest tylko interfejs), która to fabryka będzie dbała o "singletonowatość" danej klasy.

Zresztą tak działają JavaBeany w Springu.

Z drugiej strony pisanie fabryki, testowanie fabryki, poprawianie fabryki itd jest stratą czasu w momencie, gdy wiemy, że dany obiekt MUSI wystąpić tylko raz. Przykłady takich obiektów:

  • klasa reprezentująca monitor
  • Log
  • wszelkiej maści słuchacze klawiatury, myszy itp.
0

poza tym, fabryki to chyba zazwyczaj tez swego rodzaju singletony :)

0

@quetzalcoatl, niekoniecznie. Cała sztuka polega na tym, że fabryka może nie być singletonem. Wystarczy coś takiego:

class Fabryka{
   public static Object dajInstancje(){
     //...
   }
}

nie trzeba wtedy tworzyć obiektów, wystarczy tylko używać metod statycznych.
Jeszcze inne podejście to przekazanie zarządzania fabrykami do frameworku, który już w "bebechu" będzie miał jakiś singleton do konfiguracji fabryk. Możliwości jest dość dużo, a singletonów należy używać rozsądnie.

0
//gdzies tam mamy klase powiedzmy Database ktora mniej wiecej wiadomo do czego moze nam sluzyc
JakasKlasa::metoda()
{
  Database * db;
  //db = new Database;
  //db = Database::getSingleton();
  //cos tam robimy z db
}

Jedna mala poprawka:

JakasKlasa::metoda()
{
  Database * db;
  db = Database::getSingleton();
  //cos tam robimy z db
  db->blabla();
  DataBase::releaseSingleton();
}

Przy korzystaniu z singletona nie powolujemy go za pomoca new tylko za pomoca metody statycznej, ktora powoluje instancje klasy i inkrementuje ilosc "powolan". Po co? Ano po to ze nie korzystamy takze z delete tylko znowu z metody statycznej i dlatego jesli singleton jest "powolywany" z kilku obiektow to nie wszystkie "usuniecia" powoduja rzeczywiste usuniecie obiektu a tylko dekrementacje licznika "powolan". Dopiero jak licznik usiagnie 0 usuwamy obiekt singletona.

Singletona fajnie jest uzyc byle nie zbyt czesto. Typowym przykladem uzycia singletona moze byc obiekt obslugujacy polaczenie i wymiane danych z baza danych. Wszystkie obiekty w programie korzystaja sobie tylko z jednego polaczenia z db.

0

koziolek - czepialem sie wlasciwie tego, ze fabryki sa wlasnie zazwyczaj albo singletonami albo w 100% metody statyczne.. czyli defacto sa jedynie opakowaniem, 'ladniejsza forma' bibliotek/modulow, tak samo jak singletony :) oczywiscie, fabryki nie-single nie-static tez sie trafiaja..

egon - imho, nikt nie prosil o wyjasnienia implementacji.. podejrzewam ze wszyscy tu obecni sa to w stanie napisac w 15-20 sekund, nawet jesli wyrwani ze snu w srodku nocy..

0
quetzalcoatl napisał(a)

egon - imho, nikt nie prosil o wyjasnienia implementacji.. podejrzewam ze wszyscy tu obecni sa to w stanie napisac w 15-20 sekund, nawet jesli wyrwani ze snu w srodku nocy..

Dzieki za zwrocenie uwagi, zauwazylem jednak ze do implementacji zakradl sie maly bug, wiec pozwolilem sobie go poprawic i wyjasnic.

0

EgonOlsen ~ W "przykladzie" chodzilo o to, ze Singleton rozni sie od "zwyklej" klasy tylko sposobem uzyskiwania obiektu, i tak dla singletona uzyskujesz go statyczna metoda (w przykladzie: Database::getSingleton()) a dla zwyklej klasy operatorem new (w przykladzie jest to new Database).

Co do przykladu tej Fabryki to w moim przekonaniu klasa statyczna (w rozumieniu jaki jest np w C# - klasa static ma wszystko static) nie rozni sie niczym od Singletona :)

0

@Wolverine, dużo zależy od tego w jaki sposób wywoływane są metody statyczne. Czy klasa jest ładowana do pamięci na stałe, czy za każdym wywołaniem niejawnie jest tworzony obiekt i dopiero następuje wywołanie. W przypadku singletona masz pewność, że za każdym razem jest to ten sam obiekt.

0
Koziołek napisał(a)

@Wolverine, dużo zależy od tego w jaki sposób wywoływane są metody statyczne. Czy klasa jest ładowana do pamięci na stałe, czy za każdym wywołaniem niejawnie jest tworzony obiekt i dopiero następuje wywołanie. W przypadku singletona masz pewność, że za każdym razem jest to ten sam obiekt.

jesli wiesz ze to jest singleton :) a w praktyce, rzadko kiedy wiesz na pewno :) widzialem juz 'singletona' ktorego getinstance zajmowalo sie jego wymienianiem na nowy co godzine, bo ktos sobie wymyslil ze to bedzie ciekawy sposob na rotacje logow :)

0
quetzalcoatl napisał(a)

widzialem juz 'singletona' ktorego getinstance zajmowalo sie jego wymienianiem na nowy co godzine, bo ktos sobie wymyslil ze to bedzie ciekawy sposob na rotacje logow :)

Hmm, powinna byc jakas fabryka/metoda fabryczna ktorej nazwa jednoznacznie mowi, ze nie koniecznie zawsze zwraca ten sam obiekt (getCurrentLogInstance() czy cos w ten desen). Singleton to nie szczegol implementacyjny a raczej kontrakt ktory mowi, ze jest tylko jeden obiekt, dzieki czemu moge sobie zapisac ten obiekt w jakiejs referencji np zeby nie musiec wklepywac ciagle Klasa::getInstance(). Slowko Current w metodzie juz mi daje do myslenia, ze nie zawsze zwroci ona tego samego.

Imo :)

0

Czy mogę nazwać singletonem obiekt który jest jeden globalny ale zawiera tylko funkcje lub tylko dane do odczytu ?

0

@a4tech, o ile istnieje możliwość utworzenia drugiej instancji obiektu to nie. Jeżeli programista ma dbać o to by obiekt był singletonem poprzez pamiętanie, że jedna instancja juz istnieje to nie jest to singleton.

0

Poza tym w OOP nie powinno się mieć dostępu do danych obiektu z zewnątrz, Singleton jakby nie patrzeć jest wzorcem OOP, ale to tylko szczegół.

0

Nie pojmuje jak to nie powinno się mieć dostępu do danych z zewnątrz ?

Chodzi mi o obiekt który jest tak skonstruowany że jest jeden, aczkolwiek nie posiada żadnych funkcji a wszystkie dane tylko ma do odczytu. Czy jest to prawidłowe czy jest to jakiś rodzaj błedu oo?

0

@a4tech, teoretycznie jest to rodzaj błędu jednak w praktyce tego typu obiekty są stosowane do na przykład składowania danych z bazy.
Inna sprawa, że o ile w C++ masz dostęp do prawidłowego zamiennika czyli struktury to w Javie już nie ma takiego tworu.

0

Nie pobieraj od obiektu danych żeby coś na nich zrobić tylko każ temu obiektowi to zrobić. Główna zasada OOP. A po co? Ano po to żeby uniezależnić od siebie implementacje obiektów. Oczywiście w niektórych sytuacjach jest to trudne do osiągnięcia ale należy o tym pamiętać.

Polecam wchłonąć jakąś książke o OOP, wtedy dowiesz się, że taki "extends" z Javy czy cały polimorfizm można o kant d**y rozbić bo w większości wypadkach tworzony jest nieobiektowy kod. :)

0

Mozecie jakas ksiazke o oop polecic ?
[quote]
Nie pobieraj od obiektu danych żeby coś na nich zrobić tylko każ temu obiektowi to zrobić. [/quote]

Ale przecież zawsze potrzebne są jakieś dane wejściowe więc ta zasada wydaje mi się z gruntu fałszywa.

Może czegoś nie zrozumiałem. Ale jeśli mam klase monitor to musze pobrać dane o pozycji palca aby klasa monitor dobrze zareagowała.

0

Nie pobieraj od obiektu danych żeby coś na nich zrobić tylko każ temu obiektowi to zrobić.

Zatem skąd wziąć dane które obiekt ma przetworzyć w sobie? Raczej należy suche dane obudować przez mechanizm udostępniający. Zresztą powiązanie danych i pracy na nich w jednym obiekcie jest dość karkołomne w sytuacji gdy trzeba zmienić któryś z fragmentów. W MVC Model zawiera tylko te funkcjonalności, które tracą sens bez danych zazwyczaj jest to walidacja i definicja sposobu składowania (ale bez obsługi).

Polecam wchłonąć jakąś książke o OOP, wtedy dowiesz się, że taki "extends" z Javy czy cały polimorfizm można o kant d**y rozbić bo w większości wypadkach tworzony jest nieobiektowy kod.

Akurat polimorfizm jest bardzo rozsądnym rozwiązaniem ponieważ pozwala na wyniesieni "do góry" pewnych wspólnych zachowań jednocześnie pozwala na zróżnicowanie działania poszczególnych obiektów. To że nie każdy wie jak tego użyć to inna sprawa.

1 użytkowników online, w tym zalogowanych: 0, gości: 1