Pytanie Co jest tak złego w singletonach? [Zamknięte]


The wzór singletonowy jest w pełni opłaconym członkiem GoF„s wzory księgi, ale ostatnio wydaje się raczej osierocony przez świat programistów. Nadal używam wielu singletonów, szczególnie dla klasy fabryki chociaż musisz być ostrożny w kwestii wielowątkowości (jak każda klasa), nie rozumiem, dlaczego są tak okropne.

Stack Overflow szczególnie wydaje się zakładać, że wszyscy zgadzają się, że Singletonowie są źli. Czemu?

Proszę, poprzyj swoje odpowiedzi "fakty, referencje lub specjalistyczna wiedza"


1737


pochodzenie


Muszę powiedzieć, że używając singletonowego projektu ostatnio mnie spłonęło, ponieważ próbowałem dostosować kod. Tak jak robię to w wolnym czasie, jestem prawie zbyt leniwy, aby to zmienić. Złe wieści o wydajności. - Marcin
W odpowiedziach jest dużo "wad", ale chciałbym też zobaczyć dobre przykłady tego, kiedy wzór jest dobry, aby przeciwstawić się złym ... - DGM
Kilka miesięcy temu napisałem o tym blogu na ten temat: jalf.dk/blog/2010/03/... - i pozwól mi powiedzieć to wprost. Nie mogę osobiście pomyśleć o pojedynczej sytuacji, w której singleton jest właściwym rozwiązaniem. To nie znaczy, że taka sytuacja nie istnieje, ale ... nazywanie ich rzadkimi to niedopowiedzenie. - jalf
@AdamSmith to nie znaczy, że ty mieć do, ale to oznacza ciebie mogą dostęp do niego w ten sposób. A jeśli nie zamierzasz uzyskać do niego dostępu w ten sposób, to nie ma większego powodu, aby zrobić z tego singleton. Więc twoja argumentacja jest efektywna "nie ma nic złego w robieniu singletonu, jeśli tego nie robimy leczyć to jako singleton. Tak, świetnie. Mój samochód również nie zanieczyszcza, jeśli nie będę w nim jeździł. Ale łatwiej jest po prostu nie kupić samochodu w pierwszej kolejności. ;) (pełne ujawnienie: właściwie nie mam samochodu) - jalf
Najgorszą częścią tego całego tematu jest to, że ludzie, którzy nienawidzą singletonów rzadko udzielają konkretnych sugestii co do tego, czego używać. Łącza do artykułów w czasopismach i samodzielnie publikowanych blogów przez cały ten artykuł SO, na przykład, idą w kółko o tym, dlaczego nie używać singletonów (i wszystkie są doskonałe powody), ale są bardzo szczupłe w przypadku wymiany. Mnóstwo handware'u. Ci z nas, którzy próbują uczyć nowych programistów, dlaczego nie korzystać z singletonów, nie mają wielu dobrych kontrprzykładów, które mogłyby zostać udowodnione przez osoby trzecie, a jedynie wymyślone przykłady. To jest męczące. - Ti Strga


Odpowiedzi:


Parafraza od Briana Buttona:

  1. Zwykle są używane jako globalna instancja, dlaczego jest tak źle? Ponieważ ukrywasz zależności swojej aplikacji w kodzie, zamiast eksponować je za pośrednictwem interfejsów. Stworzenie czegoś globalnego, aby uniknąć jego przekazywania to zapach kodu.

  2. Naruszają zasada jednej odpowiedzialności: z racji tego, że kontrolują one swoje własne stworzenie i cykl życia.

  3. Z natury powodu ściśle kodują sprzężony. To sprawia, że ​​ich testowanie jest raczej trudne w wielu przypadkach.

  4. Niosą stan na cały okres użytkowania aplikacji. Kolejny hit do testowania, ponieważ możesz skończyć z sytuacją, w której trzeba zamówić testy, co jest dużym, nie ma dla testów jednostkowych. Czemu? Ponieważ każdy test jednostkowy powinien być niezależny od drugiego.


1148



Nie zgadzam sie z Toba. Ponieważ komentarze są dozwolone tylko dla 600 znaków, napisałem post na blogu, aby móc to skomentować, proszę zobaczyć poniższy link. jorudolph.wordpress.com/2009/11/22/singleton-considerations - Johannes Rudolph
W punkcie 1 i 4, wydaje mi się, że singletony są użyteczne, a właściwie prawie idealne do buforowania danych (zwłaszcza z DB). Zwiększenie wydajności znacznie przewyższa złożoność procesu modelowania testów jednostkowych. - Dai Bok
@Dai Bok: "buforowanie danych (zwłaszcza z DB)" użyj wzoru proxy, aby to zrobić ... - paxos1977
Wow, świetne odpowiedzi. Prawdopodobnie użyłem tu zbyt agresywnego sformułowania, więc proszę pamiętać, że odpowiadałem na źle przygotowane pytanie. Moja odpowiedź miała być krótką listą "anty-wzorców", które wynikają ze złego użycia Singletona. Pełne ujawnienie informacji; Ja też używam Singletonów od czasu do czasu. Jest więcej neutralnie zadanych pytań na temat SO, które byłyby doskonałym forum dla kiedy Singletons można uznać za dobry pomysł. Na przykład, stackoverflow.com/questions/228164/... - Jim Burger
Nie są one idealne do buforowania w środowisku wielowątkowym. Możesz łatwo pokonać pamięć podręczną z wieloma wątkami walczącymi o ograniczone zasoby. [utrzymywane przez singleton] - monksy


Singletony rozwiązują jeden (i tylko jeden) problem.

Spór o zasoby.

Jeśli masz jakieś zasoby, które

(1) może mieć tylko jedno wystąpienie, i

(2) musisz zarządzać tą pojedynczą instancją,

potrzebujesz singel.

Nie ma wielu przykładów. Plik dziennika jest duży. Nie chcesz po prostu porzucić pojedynczego pliku dziennika. Chcesz przepłukać, zsynchronizować i zamknąć poprawnie. Jest to przykład pojedynczego udostępnionego zasobu, którym należy zarządzać.

Rzadko zdarza się, że potrzebujesz singletona. Powodem, dla którego są złe, jest to, że czują się jak światowy i są w pełni opłaconym członkiem GoF Wzorce projektowe książka.

Kiedy myślisz, że potrzebujesz globalnego, prawdopodobnie popełnisz straszny błąd w projektowaniu.


399



Sprzęt jest również dobrym przykładem? Systemy wbudowane mają dużo sprzętu, który może używać singletonów - a może jednego dużego? <grin> - Jeff
Kompletnie się zgadzam. Jest wiele zdeterminowanych "ta praktyka jest zła", mówiących bez wahania, że ​​praktyka może mieć swoje miejsce. Często praktyka jest tylko "zła", ponieważ często jest niewłaściwie używana. Nie ma nic z natury nie tak z wzorem Singleton, o ile jest odpowiednio zastosowany. - Damovisa
Prawdziwe, oparte na zasadzie pojedynczej pojedynki są bardzo rzadkie (a kolejka drukarki na pewno nie jest jedna, a nie jest to plik dziennika - patrz log4j). Częściej niż nie, sprzęt jest singleton przez zbieg okoliczności, a nie z zasady. Cały sprzęt podłączony do komputera to w najlepszym przypadku przypadkowy singleton (pomyśl o wielu monitorach, myszach, drukarkach, kartach dźwiękowych). Nawet detektor cząstek o wielkości 500 milionów jest pojedynczym przypadkiem i ograniczeniami budżetowymi - które nie mają zastosowania w oprogramowaniu, a więc: nie jest to singleton. W telekomunikacji ani numer telefonu, ani telefon fizyczny nie są singletonami (myślę, że ISDN, call center). - digitalarbeiter
Sprzęt może mieć tylko jedno wystąpienie różnych zasobów, ale sprzęt nie jest oprogramowaniem. Nie ma żadnego powodu, aby pojedynczy port szeregowy na płycie rozwojowej miał być modelowany jako Singleton. Rzeczywiście, jego modelowanie utrudni tylko portowanie do nowej płyty z dwoma portami! - dash-tom-bang
Napisałbyś dwie identyczne klasy, powielając dużo kodu, żebyś mógł mieć dwa singletony reprezentujące dwa porty? A może po prostu użyć dwóch globalnych obiektów SerialPort? Co powiesz na to, żeby w ogóle nie modelować sprzętu jako zajęć? I dlaczego używałbyś singletonów, co również oznacza globalny dostęp? Czy chcesz każdy funkcjonować w kodzie, aby mieć dostęp do portu szeregowego? - jalf


Niektóre kodowanie snobów patrzy na nich jak na gloryfikowaną globalność. W ten sam sposób, w jaki wielu ludzi nienawidzi iść do oświadczenie są inni, którzy nienawidzą idei kiedykolwiek używania światowy. Widziałem wielu programistów, którzy robią wszystko, aby uniknąć światowy ponieważ rozważali użycie jednego jako przyznania się do porażki. Dziwne ale prawdziwe.

W praktyce Singel wzór jest tylko techniką programowania, która jest użyteczną częścią twojego zestawu narzędzi koncepcji. Od czasu do czasu może się okazać, że jest to idealne rozwiązanie, a więc użyj go. Ale używasz go tylko po to, byś mógł pochwalić się używaniem wzór projektu jest tak samo głupi, jak odmowa użycia go, ponieważ jest po prostu światowy.


307



Niepowodzenie w Singleton polega na tym, że ludzie używają ich zamiast globali, ponieważ są w jakiś sposób "lepsi". Problem polega na tym, (jak widzę), że rzeczy, które Singleton przedstawia w tych przypadkach, są nieistotne. (Skonstruowanie przy pierwszym użyciu jest trywialne do zaimplementowania w trybie nie-singletowym, na przykład, nawet jeśli nie używa tego konstruktora). - dash-tom-bang
Powodem, dla którego "my" patrzymy na nich, jest to, że "my" bardzo często postrzegamy je jako niewłaściwe i zbyt często. "My" wiemy, że mają swoje miejsce. - Bjarke Freund-Hansen
@Phil, Powiedziałeś, że "od czasu do czasu może się okazać, że jest to idealne rozwiązanie, więc używaj go". Ok, więc dokładnie w który Czy przypadek singletonu byłby przydatny? - Pacerier
@Pacerier, gdy spełnione są wszystkie następujące warunki: (1) potrzebujesz tylko jednego z czegoś, (2) musisz przekazać tę jedną rzecz jako argument w dużej liczbie wywołań metod, (3) jesteś skłonny zaakceptować Szansa, że ​​pewnego dnia będę musiała przekupić, w zamian za natychmiastowe zmniejszenie rozmiaru i złożoności twojego kodu, nie przepuszczając wszędzie niczego. - antinome
Nie wydaje mi się, żeby to odpowiadało na wszystko, po prostu mówi, że "czasami może to pasować, innym razem może nie". OK, ale dlaczego i kiedy? Co sprawia, że ​​ta odpowiedź jest czymś więcej niż argument do moderacji? - Guildenstern


Misko Hevery z Google ma kilka ciekawych artykułów na ten temat ...

Singletonowie są patologicznymi kłamcami ma przykład testu jednostkowego ilustrujący, w jaki sposób singletony mogą utrudniać wykrywanie łańcuchów zależności i uruchamianie lub testowanie aplikacji. Jest to dość skrajny przykład nadużycia, ale jego punkt widzenia jest nadal aktualny:

Singletony to nic innego jak globalny stan. Stan globalny sprawia, że ​​twoje obiekty mogą potajemnie zdobywać rzeczy, które nie są zadeklarowane w ich API, i w rezultacie Singletons sprawiają, że twoje API są patologicznymi kłamcami.

Gdzie zniknęły wszystkie Singletony podkreśla, że ​​zastrzyk polegający na uzależnieniu ułatwił dostanie się do konstruktorów, które ich wymagają, co zmniejsza ukrytą potrzebę złego, globalnego Singletona odrzuconego w pierwszym artykule.


200



Artykuły Misko na ten temat są w tej chwili najlepszą rzeczą. - Chris Mayer
Pierwsze łącze faktycznie nie rozwiązuje problemu z singletonami, ale raczej zakłada statyczną zależność wewnątrz klasy. Możliwe jest naprawienie podanego przykładu przez przekazanie parametrów, a mimo to użycie singletonów. - DGM
@DGM: Dokładnie - w rzeczywistości istnieje olbrzymi logiczny rozdźwięk między "racjonalną" częścią artykułu, a część "Singletonowie są przyczyną". - Harper Shelby
Artykuł Misko o CreditCard to skrajny przykład nadużycia tego wzoru. - Alex
Czytanie drugiego artykułu Singletony są w rzeczywistości częścią opisanego modelu obiektu. Jednak zamiast być dostępnym globalnie, są one prywatne dla obiektów Factory. - FruitBreak


Myślę, że zamieszanie spowodowane jest faktem, że ludzie nie znają prawdziwego wzoru Singleton. Nie mogę tego wystarczająco podkreślić. Singleton jest nie wzór do zawijania globali. Wzór Singleton powinien być stosowany tylko w celu zagwarantowania tego jedno i tylko jedno wystąpienie danej klasy istnieje w czasie wykonywania.

Ludzie myślą, że Singleton jest zły, ponieważ używa go do globalizacji. Właśnie z powodu tego zamieszania Singleton jest spuszczony z góry. Proszę nie mylić Singletonów z globalnymi. Jeśli zostanie użyty w celu, dla którego był przeznaczony, uzyskasz wyjątkowe korzyści ze wzoru Singleton.


103



Co to jest ta jedna instancja, dostępna w całej aplikacji? O. Światowy. "Singleton jest nie wzór do zawijania globals "jest albo naiwny albo wprowadzający w błąd, jak zgodnie z definicją, wzorzec owija klasę wokół globalnej instancji. - cHao
Oczywiście możesz utworzyć jedną instancję klasy, gdy aplikacja się uruchomi, i wstrzyknąć tę instancję, za pośrednictwem interfejsu, do wszystkiego, co jej używa. Wdrożenie nie powinno przejmować się tym, że może istnieć tylko jedna. - Scott Whitlock
@Dainius: W końcu tak naprawdę nie ma. Oczywiście, nie możesz arbitralnie zastąpić instancji innym. (Z wyjątkiem tych momentów indukujących facepalm, kiedy ty robisz. Rzeczywiście widziałem setInstance metody wcześniej.) To jednak nie ma znaczenia - że weenie, że "potrzebny" singleton również nie znał kapryśnej rzeczy na temat enkapsulacji lub co jest nie tak z zmiennym globalnym stanem, więc on pomocnie (?) dostarczył ustawiaczy dla każdego. pojedynczy. pole. (I tak, tak się dzieje los. Prawie każdy singleton, jaki widziałem na wolności, był zmienny z założenia i często tak wstydliwy). - cHao
@Dainius: W dużym stopniu już mamy. "Wolaj kompozycję od dziedziczenia" już od jakiegoś czasu. Kiedy dziedziczenie jest Jest to oczywiście najlepsze rozwiązanie, ale oczywiście możesz z niego korzystać. To samo dotyczy singletonów, globali, wątków, gotoitp. Mogą pracaw wielu przypadkach, ale szczerze mówiąc, "prace" to za mało - jeśli chcesz iść wbrew konwencjonalnej mądrości, lepiej umiesz pokazać, w jaki sposób twoje podejście jest lepszy niż konwencjonalne rozwiązania. I jeszcze nie widziałem takiego przypadku dla wzorca Singleton. - cHao
Abyśmy nie rozmawiali o sobie nawzajem, nie mówię tylko o globalnie dostępnej instancji. Jest wiele przypadków na to. To, o czym mówię (szczególnie gdy mówię "capital-S Singleton") to wzór Singleton, który osadza tę pojedynczą instancję globalną w samej klasie, ujawnia ją za pomocą getInstance lub podobnie nazwaną metodą i zapobiega istnieniu drugiej instancji. Szczerze mówiąc, w tym momencie równie dobrze możesz nie mieć jeden instancja. - cHao


Jedną z wad w przypadku singletonów jest to, że nie można ich bardzo łatwo rozszerzyć. Zasadniczo musisz zbudować coś w rodzaju wzór dekoratora lub coś takiego, jeśli chcesz zmienić swoje zachowanie. Ponadto, jeśli pewnego dnia chcesz mieć wiele sposobów zrobienia tego, zmiana może być dość bolesna, w zależności od tego, jak układasz swój kod.

Należy pamiętać, że jeśli używasz singletonów, spróbuj przekazać je każdemu, kto ich potrzebuje, zamiast mieć do nich bezpośredni dostęp ... W przeciwnym razie, jeśli kiedykolwiek wybierzesz różne sposoby robienia tego, co robi singleton, raczej trudne do zmiany, ponieważ każda klasa osadza zależność, jeśli ma bezpośredni dostęp do singletonu.

Więc w zasadzie:

public MyConstructor(Singleton singleton) {
    this.singleton = singleton;
}

zamiast:

public MyConstructor() {
    this.singleton = Singleton.getInstance();
}

Wierzę, że ten rodzaj wzorca jest nazywany iniekcja zależności i jest ogólnie uważana za dobrą rzecz.

Jak każdy wzorzec ... Zastanów się i rozważ, czy jego użycie w danej sytuacji jest niewłaściwe, czy nie ... Przepisy są zwykle łamane, a wzorce nie należy stosować bez zwłoki, bez myślenia.


71



Heh, jeśli zrobisz to wszędzie, będziesz musiał również wszędzie przekazać odniesienie do singeltonu, a tym samym nie będziesz już miał singletonu. :) (co jest zazwyczaj dobre IMO.) - Bjarke Freund-Hansen
@ BjarkeFreund-Hansen - Nonsens, o czym ty mówisz? Singleton jest po prostu instancją klasy, która jest instynktowana raz. Odwoływanie się do takiego Singletona nie kopiuje rzeczywistego obiektu, po prostu się do niego odwołuje - wciąż masz ten sam obiekt (czytaj: Singleton). - M. Mimpen
@ M.Mimpen: Nie, kapitał S Singleton (który jest tutaj omawiany) jest przykładem klasy, która (a) gwarancje że tylko jedna instancja kiedykolwiek będzie istnieć, a (b) będzie dostępna poprzez własny wbudowany globalny punkt dostępu klasy. Jeśli zadeklarowałeś, że nic nie powinno dzwonić getInstance(), a następnie (b) nie jest już całkiem prawdziwy. - cHao
@ cHao Nie podążam za tobą lub nie rozumiesz do kogo komentuję - czyli do Bjarke Freund-Hansen. Bjarke twierdzi, że posiadanie kilku odniesień do singletonu powoduje, że istnieje kilka singletonów. To z pewnością nie jest prawdą, ponieważ nie ma żadnych głębokich kopii. - M. Mimpen
@ M.Mimpen: Biorę jego komentarz, by odwołać się bardziej do semantycznego efektu. Gdy zostaniesz wyjęty spod prawa getInstance()skutecznie odrzuciłeś jedną użyteczną różnicę między wzorem Singletona a zwykłym referencją. Jeśli chodzi o resztę kodu, singleness nie jest już własnością. Tylko dzwoniący z getInstance() zawsze musi wiedzieć, a może nawet obchodzić ile tam jest przypadków. Tylko jeden dzwoniący kosztuje więcej wysiłku i elastyczności, aby klasa mogła rzetelnie wyegzekwować pojedynczość, niż to, że osoba dzwoniąca po prostu przechowuje referencję i ponownie jej używa. - cHao


Wzorzec singletonowy nie stanowi problemu sam w sobie. Problem polega na tym, że wzorzec jest często wykorzystywany przez osoby tworzące oprogramowanie za pomocą narzędzi obiektowych bez solidnego zrozumienia koncepcji OO. Kiedy singletony są wprowadzane w tym kontekście, mają tendencję do wzrostu w klasy, którymi nie można zarządzać, które zawierają metody pomocnicze dla każdego małego użytku.

Singletony są również problemem z perspektywy testowania. Mają tendencję do tego, aby izolowane testy jednostkowe były trudne do napisania. Odwrócenie sterowania (IoC) i iniekcja zależności są wzorami, które mają przezwyciężyć ten problem w sposób zorientowany na obiekt, który pozwala na testowanie jednostkowe.

W śmieci zebrane singletons środowiska może szybko stać się problemem w zakresie zarządzania pamięcią.

Istnieje również wielowątkowy scenariusz, w którym pojedynczo mogą stać się wąskim gardłem, a także zagadnieniem synchronizacji.


65



Wiem, że jest to wątek wiele lat. cześć @Kimoz u powiedział: - singletons może szybko stać się problemem w odniesieniu do zarządzania pamięcią. chciałbym bardziej szczegółowo wyjaśnić, jaki rodzaj problemu może pojawić się w związku z singleton & garbage collection. - Thomas
@Kimoz, Pytanie jest pytaniem "Dlaczego wzór singletonowy sam w sobie nie stanowi problemu?" i tylko powtórzyłeś punkt, ale nie podałeś nawet jednego ważnego przypadku użycia wzoru singleton. - Pacerier
@Thomas, ponieważ singleton z definicji istnieje tylko w jednym przypadku. Często przypisywanie jedynego odwołania do wartości null jest bardzo złożone. Można to zrobić, ale oznacza to, że w pełni kontrolujesz punkt, po którym singleton nie jest używany w twojej aplikacji. Jest to rzadkie i zazwyczaj zupełnie przeciwne do tego, czego szuka singleton entuzjasta: prosty sposób na zrobienie pojedynczej instancji zawsze dostępny. W niektórych frakcjach DI, takich jak Guice czy Dagger, nie można pozbyć się singletonu i pozostaje on na zawsze w pamięci. (Chociaż pojemnik pod warunkiem, że singletons są znacznie lepsze niż domowe). - Snicolas


Singleton zostaje zaimplementowany za pomocą metody statycznej. Osobom wykonującym testy jednostkowe unika się metod statycznych, ponieważ nie można ich wyśmiać ani upokorzyć. Większość osób na tej stronie jest zwolennikami testów jednostkowych. Ogólnie przyjętą konwencją w celu ich uniknięcia jest użycie odwrócenie sterowania wzór.


52



To brzmi bardziej jak problem z testowaniem jednostki, który może testować obiekty (jednostki), funkcje (jednostki), całe biblioteki (jednostki), ale kończy się niepowodzeniem z niczym statycznym w klasie (także jednostki). - v010dya
czy nie powinieneś mimo wszystko używać zewnętrznych referencji? Jeśli tak, to co jest problemem z singletonem, jeśli nie, czy naprawdę testujesz jednostkę? - Dainius
@Dainius: Kpiny instancje jest o wiele mniej kłopotów niż kpiny z klas. Można wyodrębnić testowaną klasę z reszty aplikacji i przetestować ją podróbką Singleton klasa. To jednak ogromnie komplikuje proces testowania. Po pierwsze, teraz musisz mieć możliwość rozładowywania klas według własnego uznania (nie jest to opcja w większości języków) lub uruchamiania nowej maszyny wirtualnej dla każdego testu (czytaj: testy mogą trwać tysiące razy dłużej). Dla dwóch osób zależność Singleton jest szczegółem implementacji, który obecnie wycieka z twoich testów. - cHao
Powermock może kpić z rzeczy statycznych. - Snicolas