Ostatnio dyskutowano o problemach z używaniem (i nadużywaniem) Singletonów. Byłem także jedną z tych osób wcześniej w mojej karierze. Widzę, na czym polega teraz problem, a jednak wciąż jest wiele przypadków, w których nie widzę fajnej alternatywy - i niewiele dyskusji na temat Singleton naprawdę ją oferuje.
Oto prawdziwy przykład z ostatniego dużego projektu, w który byłem zaangażowany:
Aplikacja była grubym klientem z wieloma osobnymi ekranami i komponentami, który wykorzystuje ogromne ilości danych ze stanu serwera, który nie jest zbyt często aktualizowany. Dane te były w zasadzie buforowane w obiekcie Singleton „manager” - budzącym lęk „globalnym stanie”. Pomysł polegał na tym, aby mieć to jedno miejsce w aplikacji, które przechowuje i synchronizuje dane, a następnie wszelkie nowe ekrany, które są otwarte, mogą po prostu odpytywać większość potrzebnych danych, bez powtarzania żądań o różne dane pomocnicze z serwera. Ciągłe żądania od serwera wymagałyby zbyt dużej przepustowości - a ja mówię o dodatkowych tysiącach dolarów rachunków za Internet tygodniowo, więc było to nie do przyjęcia.
Czy jest jakieś inne podejście, które mogłoby być odpowiednie tutaj niż posiadanie tego rodzaju obiektu pamięci podręcznej globalnego menedżera danych? Ten obiekt oficjalnie nie musi być „Singletonem”, ale koncepcyjnie ma sens, aby nim być. Co jest tutaj ładną czystą alternatywą?
źródło
Odpowiedzi:
Ważne jest, aby odróżnić tutaj pojedyncze instancje od wzorca projektowego Singleton .
Pojedyncze wystąpienia są po prostu rzeczywistością. Większość aplikacji jest zaprojektowana do pracy tylko z jedną konfiguracją na raz, jednym interfejsem użytkownika na raz, jednym systemem plików na raz i tak dalej. Jeśli istnieje wiele stanów lub danych do utrzymania, z pewnością chciałbyś mieć tylko jedną instancję i utrzymywać ją przy życiu tak długo, jak to możliwe.
Wzorzec projektowy Singleton jest bardzo specyficznym rodzajem pojedynczego wystąpienia, a konkretnie takim, który:
To właśnie z powodu tego konkretnego wyboru projektu wzór wprowadza kilka potencjalnych problemów długoterminowych:
Żaden z tych symptomów nie jest tak naprawdę endemiczny dla pojedynczych instancji, tylko wzór Singleton.
Co możesz zamiast tego zrobić? Po prostu nie używaj wzoru Singleton.
Cytując z pytania:
Ta koncepcja ma swoją nazwę, jak można wskazać, ale brzmi niepewnie. To się nazywa pamięć podręczna . Jeśli chcesz się spodobać, możesz to nazwać „pamięcią podręczną offline” lub zwykłą kopią zdalnych danych.
Pamięć podręczna nie musi być singletonem. Może być konieczne pojedyncze wystąpienie, jeśli chcesz uniknąć pobierania tych samych danych dla wielu wystąpień pamięci podręcznej; ale to nie znaczy, że naprawdę musisz ujawniać wszystko wszystkim .
Pierwszą rzeczą, którą zrobię, jest rozdzielenie różnych funkcjonalnych obszarów pamięci podręcznej na osobne interfejsy. Załóżmy na przykład, że tworzysz najgorszego na świecie klona YouTube opartego na Microsoft Access:
Tutaj masz kilka interfejsów opisujących określone typy danych, do których dana klasa może potrzebować dostępu - media, profile użytkowników i strony statyczne (takie jak strona główna). Wszystko to jest realizowane przez jedną mega-pamięć podręczną, ale projektujesz swoje indywidualne klasy tak, aby akceptowały interfejsy, więc nie obchodzi ich, jaki mają typ instancji. Instancję fizyczną inicjujesz raz, kiedy program się uruchamia, a następnie po prostu zaczynasz przekazywać instancje (rzutowane na określony typ interfejsu) za pośrednictwem konstruktorów i właściwości publicznych.
Nawiasem mówiąc, nazywa się to „ wstrzykiwaniem zależności” ; nie musisz używać Spring ani żadnego specjalnego kontenera IoC, o ile Twój ogólny projekt klasy akceptuje jego zależności od obiektu wywołującego zamiast tworzyć go samodzielnie lub odwoływać się do stanu globalnego .
Dlaczego warto korzystać z projektowania opartego na interfejsie? Trzy powody:
Ułatwia odczyt kodu; z interfejsów można dokładnie zrozumieć, od których danych zależą klasy zależne.
Jeśli i kiedy zdasz sobie sprawę, że Microsoft Access nie był najlepszym wyborem dla zaplecza danych, możesz go zastąpić czymś lepszym - powiedzmy SQL Server.
Czy i kiedy zdajesz sobie sprawę, że SQL Server nie jest najlepszym wyborem dla mediów konkretnie można zerwać implementację bez wpływu innych części systemu . Tam właśnie wkracza prawdziwa siła abstrakcji.
Jeśli chcesz pójść o krok dalej, możesz użyć kontenera IoC (środowisko DI), takiego jak Spring (Java) lub Unity (.NET). Prawie każdy framework DI będzie zarządzał całym swoim życiem, a konkretnie pozwoli ci zdefiniować konkretną usługę jako pojedynczą instancję (często nazywając ją „singletonem”, ale to tylko dla znajomości). Zasadniczo te frameworki oszczędzają większość pracy małpy polegającej na ręcznym przekazywaniu instancji, ale nie są absolutnie konieczne. Nie potrzebujesz żadnych specjalnych narzędzi do wdrożenia tego projektu.
Ze względu na kompletność powinienem zwrócić uwagę, że powyższy projekt też nie jest idealny. Kiedy masz do czynienia z pamięcią podręczną (taką, jaka jest), powinieneś mieć całkowicie oddzielną warstwę . Innymi słowy, projekt taki jak ten:
Zaletą tego jest to, że nigdy nie musisz zerwać
Cache
instancji, jeśli zdecydujesz się na refaktoryzację; możesz zmienić sposób przechowywania multimediów, po prostu wprowadzając alternatywną implementacjęIMediaRepository
. Jeśli pomyślisz o tym, jak to pasuje, zobaczysz, że wciąż tworzy tylko jedną fizyczną instancję pamięci podręcznej, więc nigdy nie musisz pobierać tych samych danych dwa razy.Nie oznacza to, że każde oprogramowanie na świecie musi być zaprojektowane zgodnie z tymi rygorystycznymi standardami wysokiej spójności i luźnego sprzężenia; zależy to od wielkości i zakresu projektu, zespołu, budżetu, terminów itp. Ale jeśli pytasz, jaki jest najlepszy projekt (do zastosowania zamiast singletona), to jest to.
PS Jak stwierdzili inni, prawdopodobnie nie jest najlepszym pomysłem, aby klasy zależne wiedziały, że używają pamięci podręcznej - to jest szczegół implementacji, o który po prostu nie powinny się przejmować. Biorąc to pod uwagę, ogólna architektura nadal wyglądałaby bardzo podobnie do tego, co pokazano powyżej, po prostu nie odnosi się do poszczególnych interfejsów jako do pamięci podręcznych . Zamiast tego nazwałbyś je Usługi lub coś podobnego.
źródło
W przypadku, gdy dajesz, wydaje się, że użycie Singletona nie jest problemem, ale symptomem problemu - większym problemem architektonicznym.
Dlaczego ekrany pytają obiekt pamięci podręcznej o dane? Buforowanie powinno być przezroczyste dla klienta. Powinna istnieć odpowiednia abstrakcja do dostarczania danych, a implementacja tej abstrakcji może wykorzystywać buforowanie.
Problem prawdopodobnie polega na tym, że zależności między częściami systemu nie są poprawnie skonfigurowane, i to prawdopodobnie jest systemowe.
Dlaczego ekrany muszą wiedzieć, skąd biorą swoje dane? Dlaczego ekrany nie są wyposażone w obiekt, który może spełnić ich żądania danych (za którymi ukryta jest pamięć podręczna)? Często odpowiedzialność za tworzenie ekranów nie jest scentralizowana, więc nie ma wyraźnego sensu wstrzykiwania zależności.
Ponownie przyglądamy się problemom architektonicznym i projektowym na dużą skalę.
Ponadto bardzo ważne jest, aby zrozumieć, że czas życia obiektu można całkowicie oddzielić od sposobu znalezienia obiektu do użytku.
Pamięć podręczna będzie musiała żyć przez cały okres istnienia aplikacji (aby była przydatna), więc okres istnienia obiektu to Singleton.
Problem z Singletonem (przynajmniej powszechną implementacją Singletona jako statycznej klasy / właściwości) polega na tym, jak inne klasy, które go używają, szukają go.
W przypadku statycznej implementacji Singleton, konwencja polega na tym, aby po prostu używać go w dowolnym miejscu. Ale to całkowicie ukrywa zależność i ściśle łączy dwie klasy.
Jeśli przekażemy zależności klasie, ta zależność jest wyraźna i cała klasa konsumująca musi mieć wiedzę na temat umowy, z której może skorzystać.
źródło
Napisałem cały rozdział dotyczący właśnie tego pytania. Głównie w kontekście gier, ale większość z nich powinna obowiązywać poza grami.
tl; dr:
Wzór Gang of Four Singleton ma dwie rzeczy: zapewnia wygodny dostęp do obiektu z dowolnego miejsca i zapewnia, że można utworzyć tylko jedną jego instancję. W 99% przypadków liczysz się tylko z pierwszą połową tego, a jazda kartą w drugiej połowie, aby to zrobić, stanowi niepotrzebne ograniczenie.
Oprócz tego istnieją lepsze rozwiązania zapewniające wygodny dostęp. Uczynienie obiektu globalnym jest nuklearną opcją rozwiązania tego problemu i ułatwia zniszczenie twojej enkapsulacji. Wszystko, co złe w globals, odnosi się całkowicie do singletonów.
Jeśli używasz go tylko dlatego, że masz wiele miejsc w kodzie, które muszą dotykać tego samego obiektu, spróbuj znaleźć lepszy sposób, aby nadać go tylko tym obiektom bez narażania go na całą bazę kodu. Inne rozwiązania:
Porzuć to całkowicie. Widziałem wiele klas singletonów, które nie mają żadnego stanu i są po prostu mnóstwem funkcji pomocniczych. Te wcale nie potrzebują instancji. Po prostu uczyń je funkcjami statycznymi lub przenieś je do jednej z klas, które funkcja przyjmuje jako argument.
Math
Gdybyś mógł, nie potrzebowałbyś specjalnej klasy123.Abs()
.Przekaż to. Prostym rozwiązaniem, jeśli metoda wymaga jakiegoś innego obiektu, jest po prostu przekazanie go. Nie ma nic złego w przekazywaniu niektórych obiektów.
Umieść to w klasie podstawowej. Jeśli masz wiele klas, z których wszystkie potrzebują dostępu do jakiegoś specjalnego obiektu i mają wspólną klasę podstawową, możesz uczynić ten obiekt członkiem w bazie. Kiedy go zbudujesz, przekaż obiekt. Teraz wszystkie obiekty pochodne mogą je uzyskać, gdy są potrzebne. Jeśli zapewnisz mu ochronę, upewnisz się, że obiekt nadal pozostaje zamknięty.
źródło
Problemem nie jest stan globalny sam w sobie.
Naprawdę musisz się tylko martwić
global mutable state
. Skutki uboczne nie mają wpływu na stan stały i dlatego stanowią mniejszy problem.Głównym problemem związanym z singletonem jest to, że dodaje sprzężenie, a tym samym utrudnia takie testy (er). Możesz zredukować sprzężenie, pobierając singleton z innego źródła (np. Z fabryki). Umożliwi to oddzielenie kodu od konkretnej instancji (chociaż stajesz się bardziej sprzężony z fabryką (ale przynajmniej fabryka może mieć alternatywne implementacje dla różnych faz)).
W twojej sytuacji myślę, że możesz sobie z tym poradzić, o ile twój singleton faktycznie implementuje interfejs (aby alternatywę można było zastosować w innych sytuacjach).
Ale kolejną poważną wadą singletonów jest to, że gdy są one w miejscu, usuwanie ich z kodu i zastępowanie ich czymś innym staje się prawdziwym trudnym zadaniem (znów pojawia się to sprzężenie).
źródło
le weekend
oops, który jest jednym z naszych). Dzięki :-)Co wtedy Ponieważ nikt tego nie powiedział: Przybornik . To jest, jeśli chcesz zmienne globalne .
Ale zgadnij co? To singleton!
A czym jest singleton?
Może tam zaczyna się zamieszanie.
Dla mnie singleton jest obiektem wymuszonym, aby mieć tylko jedną instancję i zawsze. Możesz uzyskać do niego dostęp w dowolnym miejscu i czasie, bez konieczności jego tworzenia. Dlatego jest tak ściśle związany z
static
. Dla porównaniastatic
jest to w zasadzie to samo, tyle że nie jest to instancja. Nie musimy go tworzyć, nie możemy nawet, ponieważ jest on przydzielany automatycznie. I to może powodować problemy.Z mojego doświadczenia, po prostu zastąpienie
static
Singleton rozwiązało wiele problemów w średniej wielkości patchworku, w którym pracuję. Oznacza to tylko, że ma pewne zastosowanie w przypadku źle zaprojektowanych projektów. Myślę, że jest zbyt wiele dyskusji na temat tego, czy wzór singletonu jest przydatny, czy też nie, i tak naprawdę nie mogę się kłócić, czy rzeczywiście jest zły . Ale nadal istnieją dobre argumenty przemawiające za singletonem w stosunku do metod statycznych .Jedyne, co jestem pewien, że jest złe w singletonach, to kiedy ich używamy, ignorując dobre praktyki. To rzeczywiście coś, z czym nie jest tak łatwo sobie poradzić. Ale złe praktyki można zastosować do dowolnego wzorca. I wiem, że zbyt ogólne jest stwierdzenie, że ... Mam na myśli, że jest po prostu zbyt wiele.
Nie zrozum mnie źle!
Mówiąc najprościej, podobnie jak globalne zmienne , wciąż należy unikać singletonów . Zwłaszcza dlatego, że są nadmiernie wykorzystywane. Ale globalnych zmienności nie da się zawsze uniknąć i powinniśmy ich użyć w tym ostatnim przypadku.
W każdym razie istnieje wiele innych sugestii innych niż Przybornik i podobnie jak Przybornik, każda z nich ma swoją aplikację ...
Inne alternatywy
Najlepszy artykuł Właśnie przeczytałem o pojedynczych sugeruje lokalizatora usług jako alternatywę. Dla mnie jest to w zasadzie „ Zestaw narzędzi statycznych ”, jeśli wolisz. Innymi słowy, ustaw Service Locator jako Singleton, a będziesz mieć Zestaw narzędzi. Jest to oczywiście sprzeczne z początkową sugestią unikania singletonu, ale to tylko w celu wymuszenia, by problem singletona polegał na tym, jak jest używany, a nie na samym schemacie.
Inni sugerują wzór fabryczny jako alternatywę. To była pierwsza alternatywa, jaką usłyszałem od kolegi i szybko ją wyeliminowaliśmy z powodu naszego globalnego var . Z pewnością ma swoje zastosowanie, ale także singletony.
Obie powyższe alternatywy są dobrymi alternatywami. Ale wszystko zależy od twojego użycia.
Teraz sugerowanie, że singletonów należy unikać za wszelką cenę, jest po prostu błędne ...
Nieprawidłowości (abstrakcyjne lub podklasy) rzeczywiście istnieją, ale co z tego? To nie jest do tego przeznaczone. O ile mi wiadomo, nie ma możliwości interfejsu . Może również istnieć wysokie sprzężenie , ale tylko dlatego, że jest powszechnie stosowane. Nie musi . W rzeczywistości samo sprzężenie nie ma nic wspólnego ze wzorem singletonu. To wyjaśnienie eliminuje już także trudność testowania. Jeśli chodzi o trudność zrównoleglenia, to zależy od języka i platformy, więc znowu nie ma problemu ze wzorem.
Praktyczne przykłady
Często widzę 2 używane, zarówno na korzyść, jak i przeciwko singletonom. Pamięć podręczna (moja sprawa) i usługa logowania .
Rejestrowanie, jak niektórzy twierdzą , jest doskonałym przykładem singletonu, ponieważ i cytuję:
Podczas gdy inni będą argumentować, że trudno jest rozwinąć usługę dziennika, gdy w końcu zdasz sobie sprawę, że tak naprawdę nie powinna to być tylko jedna instancja.
Mówię, że oba argumenty są prawidłowe. Problem tutaj znowu nie dotyczy wzoru singletonów. To, czy refaktoryzacja stanowi realne ryzyko, zależy od decyzji architektonicznych i wagi. Jest to kolejny problem, gdy zwykle refaktoryzacja jest ostatnim niezbędnym środkiem naprawczym.
źródło
java.awt.Toolkit
. Chodzi mi o to samo:Toolbox
brzmi jak chwyt niepowiązanych ze sobą kawałków, a nie spójna klasa z jednym celem. Nie brzmi dla mnie jak dobry projekt. (Zauważ, że artykuł, do którego się odwołujesz, pochodzi z 2001 r., Zanim zastrzyki zależności i pojemniki DI stały się powszechne).Moim głównym problemem związanym ze wzorem singletonów jest to, że bardzo trudno jest napisać dobre testy jednostkowe dla twojej aplikacji.
Każdy komponent zależny od tego „menedżera” robi to, sprawdzając swoją instancję singleton. A jeśli chcesz napisać test jednostkowy dla takiego komponentu, musisz wstrzyknąć dane do tej instancji singletonu, co może nie być łatwe.
Jeśli natomiast „menedżer” zostanie wstrzyknięty do zależnych komponentów przez parametr konstruktora, a komponent nie zna konkretnego typu menedżera, tylko interfejs lub abstrakcyjną klasę bazową, którą implementuje menedżer, to jednostka test może dostarczyć alternatywne implementacje menedżera podczas testowania zależności.
Jeśli używasz kontenerów IOC do konfigurowania i tworzenia instancji składników tworzących aplikację, możesz łatwo skonfigurować kontener IOC, aby utworzyć tylko jedną instancję „menedżera”, umożliwiając osiągnięcie tego samego, tylko jednej instancji kontrolującej globalną pamięć podręczną aplikacji .
Ale jeśli nie przejmujesz się testami jednostkowymi, wzór singletonu może być całkowicie w porządku. (ale i tak bym tego nie zrobił)
źródło
Singleton nie jest zasadniczo zły , w tym sensie, że każdy projekt komputerowy może być dobry lub zły. Może być tylko poprawne (daje oczekiwane wyniki) lub nie. Może być również przydatny lub nie, jeśli sprawia, że kod jest wyraźniejszy lub bardziej wydajny.
Jednym z przypadków, w których singletony są przydatne, jest to, że reprezentują one istotę naprawdę wyjątkową. W większości środowisk bazy danych są unikalne, tak naprawdę jest tylko jedna baza danych. Łączenie się z tą bazą danych może być skomplikowane, ponieważ wymaga specjalnych uprawnień lub przejścia przez kilka typów połączeń. Zorganizowanie tego połączenia w singleton prawdopodobnie ma sens tylko z tego powodu.
Ale musisz także upewnić się, że singleton naprawdę jest singletonem, a nie zmienną globalną. Ma to znaczenie, gdy pojedyncza, unikalna baza danych to tak naprawdę 4 bazy danych, po jednej dla produkcji, instalacji, rozwoju i testowania. Singleton bazy danych ustali, z którym z nich powinien się połączyć, złap pojedynczą instancję dla tej bazy danych, połącz ją w razie potrzeby i zwróć do dzwoniącego.
Kiedy singleton nie jest tak naprawdę singletonem (wtedy większość programistów się denerwuje), jest to leniwie utworzony globalny, nie ma możliwości wstrzyknięcia poprawnej instancji.
Inną przydatną cechą dobrze zaprojektowanego wzoru singletonu jest to, że często nie można go zaobserwować. Dzwoniący prosi o połączenie. Usługa, która ją zapewnia, może zwrócić obiekt w puli, a jeśli wykonuje test, może utworzyć nowy dla każdego obiektu wywołującego lub zamiast tego udostępnić obiekt próbny.
źródło
Użycie wzorca singletonu reprezentującego rzeczywiste obiekty jest całkowicie dopuszczalne. Piszę dla iPhone'a, a w Cocoa Touch jest wiele singletonów. Sama aplikacja jest reprezentowana przez singletona klasy
UIApplication
. Jest tylko jedna aplikacja, więc należy ją przedstawić za pomocą singletona.Używanie singletonu jako klasy menedżera danych jest w porządku, pod warunkiem, że jest odpowiednio zaprojektowane. Jeśli jest to zbiór właściwości danych, nie jest to lepszy niż zasięg globalny. Jeśli jest to zestaw pobierających i ustawiających, to lepiej, ale nadal nie jest świetny. Jeśli jest to klasa, która naprawdę zarządza całym interfejsem do danych, w tym być może pobiera dane zdalne, buforuje, konfiguruje i odrzuca ... To może być bardzo przydatne.
źródło
Singletony to tylko odwzorowanie architektury zorientowanej na usługi w programie.
Interfejs API jest przykładem singletona na poziomie protokołu. Dostęp do Twittera, Google itp. Uzyskuje się za pośrednictwem singletonów. Dlaczego singletony stają się złe w programie?
To zależy od tego, jak myślisz o programie. Jeśli myślisz o programie jako o społeczeństwie usług, a nie o losowo powiązanych buforowanych instancjach, singletony mają doskonały sens.
Singletony to punkt dostępu do usług. Publiczny interfejs do ściśle powiązanej biblioteki funkcjonalności, która ukrywa być może bardzo wyrafinowaną architekturę wewnętrzną.
Więc nie widzę singletona tak różnego od fabryki. Singleton może mieć przekazane parametry konstruktora. Może być utworzony przez jakiś kontekst, który wie, jak rozwiązać domyślną drukarkę na przykład we wszystkich możliwych mechanizmach wyboru. Do testowania możesz wstawić własną próbkę. Więc może być dość elastyczny.
Klucz jest wewnętrznie w programie, kiedy wykonuję i potrzebuję trochę funkcjonalności, mogę uzyskać dostęp do singletonu z pełną pewnością, że usługa jest gotowa i gotowa do użycia. Jest to kluczowe, gdy w procesie rozpoczynają się różne wątki, które muszą przejść przez automat stanów, aby można je było uznać za gotowe.
Zazwyczaj owijałem
XxxService
klasę, która owija singleton wokół klasyXxx
. Singleton nie jest w klasieXxx
w ogóle, to wydziela się do innej klasyXxxService
. Wynika to z faktu, żeXxx
może mieć wiele instancji, choć jest to mało prawdopodobne, ale nadal chcemy, aby jednaXxx
instancja była dostępna globalnie w każdym systemie.XxxService
zapewnia miły podział problemów.Xxx
nie musi egzekwować polityki singletonów, ale możemy z tego skorzystaćXxx
jako singletonów, kiedy jest taka potrzeba.Coś jak:
źródło
Pierwsze pytanie: czy w aplikacji znajduje się wiele błędów? może zapomniałeś zaktualizować pamięć podręczną lub złą pamięć podręczną lub trudno ci ją zmienić? (Pamiętam, że aplikacja nie zmieniłaby rozmiarów, chyba że zmieniłeś też kolor ... możesz jednak zmienić kolor z powrotem i zachować rozmiar).
To, co byś zrobił, to mieć tę klasę, ale USUŃ WSZYSTKICH CZŁONKÓW STATYCZNYCH. Ok, to nie jest nessacary, ale polecam. Naprawdę po prostu inicjujesz klasę jak normalną klasę i podajesz wskaźnik. Nie marnuj powiedz ClassIWant.APtr (). LetMeChange.ANYTHINGATALL (). Andhave_no_structure ()
To więcej pracy, ale naprawdę mniej skomplikowane. Niektóre miejsca, w których nie powinieneś zmieniać rzeczy, których teraz nie możesz, ponieważ nie są już globalne. Wszystkie moje zajęcia menedżerskie są zwykłymi zajęciami, po prostu traktuj to w ten sposób.
źródło
IMO, twój przykład brzmi dobrze. Sugerowałbym faktoring w następujący sposób: obiekt pamięci podręcznej dla każdego (i za każdym) obiektu danych; obiekty pamięci podręcznej i obiekty bazy danych db mają ten sam interfejs. Daje to możliwość zamiany pamięci podręcznej do i z kodu; a ponadto daje łatwą drogę ekspansji.
Graficzny:
Akcesorium DB i pamięć podręczna mogą dziedziczyć po tym samym obiekcie lub typie kaczki, aby wyglądać jak ten sam obiekt, cokolwiek. Tak długo, jak możesz podłączyć / skompilować / przetestować i nadal działa.
To oddziela rzeczy, dzięki czemu możesz dodawać nowe pamięci podręczne bez konieczności wchodzenia i modyfikowania niektórych obiektów Uber-Cache. YMMV. IANAL. ITP.
źródło
Trochę późno na imprezę, ale i tak.
Singleton to narzędzie w przyborniku, podobnie jak wszystko inne. Mamy nadzieję, że masz więcej w zestawie narzędzi niż pojedynczy młotek.
Rozważ to:
vs
1. przypadek prowadzi do wysokiego sprzężenia itp .; Drugi sposób nie ma problemów, o których mogę powiedzieć @Aaronaught. Wszystko zależy od tego, jak z niego korzystasz.
źródło
Niech każdy ekran przejmie Menedżera w swoim konstruktorze.
Po uruchomieniu aplikacji tworzysz jedno wystąpienie menedżera i przekazujesz je.
Nazywa się to Inwersją Kontroli i pozwala zamienić kontroler przy zmianie konfiguracji i testach. Dodatkowo możesz uruchomić kilka instancji aplikacji lub jej części równolegle (dobre do testowania!). W końcu twój menedżer umrze ze swoim właścicielem (klasa startowa).
Skonstruuj więc swoją aplikację jak drzewo, na którym rzeczy powyżej posiadają wszystko, co znajduje się pod nimi. Nie wdrażaj aplikacji takich jak siatki, w których wszyscy znają się i znajdują się za pomocą globalnych metod.
źródło