Spojrzmy prawdzie w oczy. Wzór Singleton jest bardzo kontrowersyjnym tematem z hordami programistów po obu stronach ogrodzenia. Są tacy, którzy czują, że Singleton jest niczym innym jak gloryfikowaną zmienną globalną, i inni, którzy przysięgają na wzór i używają go nieustannie. Nie chcę jednak, aby Kontrowersje Singletona leżały u podstaw mojego pytania. Każdy może wziąć udział w przeciąganiu liny, walczyć i zobaczyć, kto wygra, o ile mi zależy . Próbuję powiedzieć, że nie wierzę, że istnieje jedna poprawna odpowiedź i nie próbuję celowo rozpalać kłótni partyzanckich. Interesują mnie po prostu alternatywy singletonowe, kiedy zadaję pytanie:
Czy są jakieś konkretne alternatywy dla wzoru GOF Singleton?
Na przykład wiele razy, gdy w przeszłości korzystałem ze wzorca singleton, po prostu interesuje mnie zachowanie stanu / wartości jednej lub kilku zmiennych. Stan / wartości zmiennych można jednak zachować między każdą instancją klasy przy użyciu zmiennych statycznych zamiast używania wzorca singleton.
Jaki masz inny pomysł?
EDYCJA: Naprawdę nie chcę, aby był to kolejny post o tym, jak poprawnie używać singletona. Ponownie szukam sposobów, aby tego uniknąć. Dla zabawy, ok? Chyba zadaję czysto akademickie pytanie w Twoim najlepszym głosie zwiastuna filmu: „W równoległym wszechświecie, w którym nie ma singletona, co możemy zrobić?”
źródło
Odpowiedzi:
Alex Miller w „ Patterns I Hate ” cytuje:
„Kiedy singleton wydaje się być odpowiedzią, często uważam, że rozsądniej jest:
źródło
Aby zrozumieć właściwy sposób obejścia singletonów, musisz zrozumieć, co jest nie tak z singletonami (i ogólnie ze stanem globalnym):
Singletony ukrywają zależności.
Dlaczego jest to ważne?
Ponieważ jeśli ukryjesz zależności, zwykle tracisz kontrolę nad wielkością sprzężenia.
Możesz się z tym spierać
jest prostsze niż
ale przynajmniej drugie API wyjaśnia dokładnie, kim są współpracownicy metody.
Tak więc sposobem obejścia Singletonów nie jest użycie statycznych zmiennych lub lokalizatorów usług, ale zmiana klas Singleton w instancje, które są tworzone w zakresie, w którym mają sens i są wstrzykiwane do komponentów i metod, które ich potrzebują. Możesz użyć frameworka IoC, aby sobie z tym poradzić, lub możesz to zrobić ręcznie, ale ważne jest, aby pozbyć się swojego stanu globalnego i wyraźnie określić zależności i współpracę.
źródło
Najlepszym rozwiązaniem, z jakim się spotkałem, jest użycie wzorca fabryki do konstruowania instancji klas. Używając wzorca, możesz zapewnić, że istnieje tylko jedno wystąpienie klasy, które jest współużytkowane przez obiekty, które go używają.
Wydawało mi się, że byłoby to skomplikowane w zarządzaniu, ale po przeczytaniu tego wpisu na blogu „Where Have All the Singletons Gone?” wydaje się takie naturalne. A na marginesie, bardzo pomaga to w izolowaniu testów jednostkowych.
Podsumowując, co musisz zrobić? Za każdym razem, gdy obiekt jest zależny od innego, otrzyma jego wystąpienie tylko za pośrednictwem swojego konstruktora (brak nowego słowa kluczowego w Twojej klasie).
A potem fabryka.
Ponieważ instancję fabryki utworzysz tylko raz, zostanie utworzona pojedyncza instancja exSingleton. Za każdym razem, gdy wywołasz buildNeedy, nowa instancja NeedyClass zostanie dołączona do exSingleton.
Mam nadzieję, że to pomoże. Proszę wskazać wszelkie błędy.
źródło
Spring czy jakikolwiek inny kontener IoC radzi sobie w tym całkiem nieźle. Ponieważ klasy są tworzone i zarządzane poza samą aplikacją, kontener może tworzyć pojedyncze klasy proste i wstrzykiwać je w razie potrzeby.
źródło
Nie powinieneś wychodzić z drogi, aby uniknąć jakiegokolwiek wzoru. Użycie wzoru jest decyzją projektową lub naturalnym dopasowaniem (po prostu pasuje). Projektując system, możesz wybrać, czy chcesz użyć wzoru, czy nie. Nie należy jednak wychodzić z siebie, aby uniknąć wszystkiego, co ostatecznie jest wyborem projektowym.
Nie unikam wzoru Singleton. Albo jest to odpowiednie i używam go, albo nie jest odpowiednie i nie używam go. Uważam, że to takie proste.
Odpowiedniość (lub jej brak) Singletona zależy od sytuacji. Jest to decyzja projektowa, którą należy podjąć, a jej konsekwencje należy zrozumieć (i udokumentować).
źródło
Monostate (opisany w Agile Software Development Roberta C. Martina) jest alternatywą dla singletona. W tym wzorcu wszystkie dane klasy są statyczne, ale metody pobierające / ustawiające są niestatyczne.
Na przykład:
Monostate zachowuje się podobnie jak singleton, ale robi to w sposób, w którym programista niekoniecznie jest świadomy faktu, że używany jest singleton.
źródło
Singleton wzorzec istnieje, ponieważ zdarzają się sytuacje, kiedy potrzebna jest pojedynczy obiekt dostarczenie zestawu usług .
Nawet jeśli tak jest, nadal uważam podejście do tworzenia singletonów za pomocą globalnego pola statycznego / właściwości reprezentującej instancję, za niewłaściwe. Jest to niewłaściwe, ponieważ tworzy zależność w kodzie między polem statycznym a obiektem, a nie usługami, które zapewnia obiekt.
Dlatego zamiast klasycznego, pojedynczego wzorca, polecam użycie wzorca „like” usługi z obsługiwanymi kontenerami , gdzie zamiast używać singletona przez pole statyczne, uzyskujesz do niego odwołanie za pomocą metody żądającej typu usługi.
zamiast jednego globalnego
W ten sposób, jeśli chcesz zmienić typ obiektu z singletona na inny, będziesz mieć na to łatwy czas. Dodatkową korzyścią jest to, że nie musisz przekazywać przydziału instancji obiektów do każdej metody.
Zobacz także Inversion of Control , idea polega na tym, że wystawiając pojedyncze elementy bezpośrednio konsumentowi, tworzysz zależność między konsumentem a instancją obiektu, a nie usługami obiektowymi dostarczanymi przez obiekt.
Moim zdaniem jest to, aby w miarę możliwości ukrywać stosowanie wzorca singleton, ponieważ nie zawsze można go uniknąć lub jest to pożądane.
źródło
Jeśli używasz Singletona do reprezentowania pojedynczego obiektu danych, możesz zamiast tego przekazać obiekt danych jako parametr metody.
(chociaż twierdziłbym, że jest to niewłaściwy sposób używania Singletona w pierwszej kolejności)
źródło
Jeśli Twoim problemem jest to, że chcesz zachować stan, potrzebujesz klasy MumbleManager. Przed rozpoczęciem pracy z systemem klient tworzy MumbleManager, gdzie Mumble to nazwa systemu. Dzięki temu państwo zostaje zachowane. Jest szansa, że Twój MumbleManager będzie zawierał torbę z majątkiem, która zawiera Twój stan.
Ten typ stylu jest bardzo podobny do C i niezbyt obiektowy - przekonasz się, że wszystkie obiekty definiujące Twój system będą miały odniesienie do tego samego MumbleManagera.
źródło
Użyj zwykłego obiektu i obiektu fabrycznego. Fabryka jest odpowiedzialna za nadzorowanie instancji i zwykłych szczegółów obiektu tylko z informacjami o konfiguracji (zawiera na przykład) i zachowaniem.
źródło
Właściwie, jeśli projektujesz od zera, unikając Singeltonów, możesz nie musieć obejść się bez używania Singletonów przy użyciu zmiennych statycznych. Używając zmiennych statycznych, tworzysz również mniej więcej Singleton, jedyną różnicą jest to, że tworzysz różne instancje obiektów, jednak wewnętrznie zachowują się one tak, jakby używały Singletona.
Czy możesz podać szczegółowy przykład, gdzie używasz Singletona lub gdzie jest obecnie używany Singleton i próbujesz go uniknąć? Może to pomóc ludziom znaleźć bardziej wyszukane rozwiązanie, jak można by w ogóle poradzić sobie z tą sytuacją bez Singletona.
Przy okazji, ja osobiście nie mam problemów z singletonami i nie mogę zrozumieć problemów innych ludzi z singletonami. Nie widzę w nich nic złego. To znaczy, jeśli ich nie nadużywasz. Każda użyteczna technika może zostać nadużyta, a jeśli zostanie nadużyta, doprowadzi to do negatywnych skutków. Inną często nadużywaną techniką jest dziedziczenie. Wciąż nikt nie powiedziałby, że dziedziczenie jest czymś złym tylko dlatego, że niektórzy ludzie strasznie go nadużywają.
źródło
Osobiście dla mnie o wiele bardziej rozsądnym sposobem implementacji czegoś, co zachowuje się jak singleton, jest użycie w pełni statycznej klasy (statyczne składowe, statyczne metody, statyczne właściwości). Najczęściej implementuję to w ten sposób (nie mogę wymyślić żadnych różnic w zachowaniu z punktu widzenia użytkownika)
źródło
Myślę, że najlepszym miejscem do nadzorowania singletona jest poziom projektowania klas. Na tym etapie powinieneś być w stanie zmapować interakcje między klasami i zobaczyć, czy coś absolutnie, zdecydowanie wymaga, aby tylko 1 wystąpienie tej klasy istniało kiedykolwiek w dowolnym momencie życia aplikacji.
Jeśli tak jest, masz singletona. Jeśli rzucasz singletony dla wygody podczas kodowania, to naprawdę powinieneś wrócić do swojego projektu i również przestać kodować te singletony :)
I tak, mam tu na myśli raczej słowo „policja” niż „unikać”. Singleton nie jest czymś, czego należy unikać (tak samo, jak zmienne goto i globalne nie są czymś, czego należy unikać). Zamiast tego powinieneś monitorować jego użycie i upewnić się, że jest to najlepsza metoda na skuteczne wykonanie tego, co chcesz.
źródło
Używam singletona głównie jako „kontenera metod”, bez żadnego stanu. Jeśli muszę współdzielić te metody z wieloma klasami i chcę uniknąć obciążenia związanego z tworzeniem instancji i inicjalizacją, tworzę kontekst / sesję i inicjalizuję wszystkie tam klasy; wszystko, co odnosi się do sesji, ma również dostęp do zawartego w niej „singletona”.
źródło
Ponieważ nie programowałem w środowisku intensywnie zorientowanym obiektowo (np. Java), nie jestem do końca przekonany o zawiłościach dyskusji. Ale zaimplementowałem singleton w PHP 4. Zrobiłem to jako sposób na stworzenie procedury obsługi bazy danych „czarnej skrzynki”, która jest automatycznie inicjowana i nie trzeba było przekazywać wywołań funkcji w górę iw dół w niepełnym i nieco zepsutym frameworku.
Po przeczytaniu kilku linków wzorców singletonów nie jestem do końca pewien, czy zaimplementowałbym to ponownie w taki sam sposób. To, co było naprawdę potrzebne, to wiele obiektów ze współdzieloną pamięcią (np. Rzeczywisty uchwyt bazy danych) i właśnie w to zamieniło się moje wywołanie.
Podobnie jak w przypadku większości wzorców i algorytmów, używanie singletona „tylko dlatego, że jest fajne” jest niewłaściwą rzeczą do zrobienia. Potrzebowałem połączenia naprawdę „czarnej skrzynki”, które zdarzyło się bardzo przypominać singletona. I IMO to sposób na rozwiązanie problemu: bądź świadomy wzorca, ale także spójrz na jego szerszy zakres i na jakim poziomie jego instancja musi być wyjątkowa.
źródło
Co masz na myśli, jakie mam techniki, aby tego uniknąć?
Aby tego „uniknąć”, oznacza to, że jest wiele sytuacji, z którymi się spotykam, w których wzorzec singletonowy jest naturalnie dobrze dopasowany, a zatem muszę podjąć pewne środki, aby złagodzić te sytuacje.
Ale nie ma. Nie muszę unikać wzorca singleton. Po prostu się nie pojawia.
źródło