Kiedy należy używać wzorca singleton zamiast klasy statycznej? [Zamknięte]

85

Nazwij względy projektowe przy podejmowaniu decyzji między użyciem pojedynczej a statycznej klasy. Robiąc to, jesteś jakby zmuszony do przeciwstawienia sobie obu, więc wszelkie kontrasty, które możesz wymyślić, są również przydatne w pokazaniu twojego procesu myślowego! Ponadto każdy ankieter lubi oglądać ilustracyjne przykłady. :)

cdleary
źródło
klasa java nie może uczynić statyczną, chyba że jest to klasa wewnętrzna
Harshana
1
Jeśli stan obiektu ma znaczenie, użyj singletona, w przeciwnym razie użyj klasy statycznej.
Levent Divilioglu

Odpowiedzi:

80
  • Singletony mogą implementować interfejsy i dziedziczyć z innych klas.
  • Singletony mogą być ładowane leniwie. Tylko wtedy, gdy jest to rzeczywiście potrzebne. Jest to bardzo przydatne, jeśli inicjalizacja obejmuje kosztowne ładowanie zasobów lub połączenia z bazą danych.
  • Singletony oferują rzeczywisty przedmiot.
  • Singletony można rozbudować do fabryki. Zarządzanie obiektami za kulisami jest abstrakcyjne, więc jest łatwiejsze w utrzymaniu i skutkuje lepszym kodem.
Tobias
źródło
2
Spójrz na ten link również: codeofdoom.com/wordpress/2008/04/20/…
Amit
4
„Pojedyncze elementy mogą być ładowane z opóźnieniem” - w języku C # konstruktor statyczny jest wywoływany tylko przy pierwszym odwołaniu do elementu statycznego. W PHP można użyć automatycznego ładowania, aby było uruchamiane tylko przy pierwszym użyciu klasy.
mpen
Statyczne inicjalizacje Java są również leniwe. Brak punktów dla singletonów.
MikeFHay
13

A co powiesz na „unikanie obu”? Singletony i klasy statyczne:

  • Może wprowadzić stan globalny
  • Połącz się ściśle z wieloma innymi klasami
  • Ukryj zależności
  • Może utrudniać izolowanie klas testów jednostkowych

Zamiast tego zapoznaj się z bibliotekami Dependency Injection i Inversion of Control Container . Kilka bibliotek IoC zajmie się zarządzaniem przez cały okres użytkowania.

(Jak zawsze, istnieją wyjątki, takie jak statyczne klasy matematyczne i metody rozszerzające C #).

TrueWill
źródło
1
Małe nitki: klasy pojedyncze są kompatybilne z technikami wstrzykiwania zależności (po prostu wstrzyknij je do swoich klas zależnych i nie muszą niczego twardo kodować) - pozwala to na mockowanie i testowanie w izolacji. Są również prawidłowym wzorcem projektowym do zarządzania zasobami, o których wiadomo, że mają ograniczoną szerokość platformy. (Klasycznym przykładem są drukarki, które nie mają zarządzania rywalizacją).
cdleary
@cdleary - zgodził się; jednak klasyczna implementacja często opuszcza Singleton.getInstance () w całym kodzie. „Pojedyncze” do zarządzania zasobami, pamięciami podręcznymi itp. Można zaimplementować za pomocą struktur POCO / POJO i kontenerów IoC, które obsługują zarządzanie okresem życia (zarejestruj typ jako okres istnienia kontenera, a każde rozwiązanie otrzyma tę samą instancję).
TrueWill
9
Jeśli chcesz zapewnić swoim Singletonom porządny pochówek, wejdź na singletonfuneralservice.com
TrueWill
1
Hide DependenciesMałe informacje dodatkowe na ten temat: Możesz zaimplementować wzorzec Inversion of Control, na przykład za pomocą Ninject . Pozwala to na użycie tylko jednej instancji typu przez powiązanie jej z a SingletonScope, co oznacza, że ​​zawsze będzie wstrzykiwać tę samą instancję, ale klasa nie będzie pojedyncza.
LuckyLikey
8

Twierdzę, że jedyną różnicą jest składnia: MySingleton.Current.Whthing () vs MySingleton.Whthing (). Stan, jak wspomniał Dawid, jest ostatecznie „statyczny” w obu przypadkach.


EDYCJA: Brygada bury przyszła z digg ... w każdym razie pomyślałem o przypadku, który wymagałby singletona. Klasy statyczne nie mogą dziedziczyć z klasy bazowej ani implementować interfejsu (przynajmniej w .Net nie mogą). Więc jeśli potrzebujesz tej funkcjonalności, musisz użyć singletona.

xanadont
źródło
7

Jedna z moich ulubionych dyskusji na ten temat znajduje się tutaj (oryginalna witryna wyłączona, teraz połączona z Internet Archive Wayback Machine ).

Podsumowując zalety elastyczności Singletona:

  • Singleton można łatwo przekształcić w fabrykę
  • Singleton można łatwo zmodyfikować, aby zwracał różne podklasy
  • może to spowodować, że aplikacja będzie łatwiejsza w utrzymaniu
Newdayrising
źródło
5

Klasa statyczna z ładunkiem zmiennych statycznych to trochę hack.

/**
 * Grotty static semaphore
 **/
 public static class Ugly {

   private static int count;

   public synchronized static void increment(){
        count++;
   }

   public synchronized static void decrement(){
        count--;
        if( count<0 ) {
            count=0;
        }
   }

   public synchronized static boolean isClear(){
         return count==0;    

    }
   }

Singleton z aktualną instancją jest lepszy.

/**
 * Grotty static semaphore
 **/
 public static class LessUgly {
   private static LessUgly instance;

   private int count;

   private LessUgly(){
   }

   public static synchronized getInstance(){
     if( instance==null){
        instance = new LessUgly();
     }
     return instance;
   }
   public synchronized void increment(){
        count++;
   }

   public synchronized void decrement(){
        count--;
        if( count<0 ) {
            count=0;
        }
   }

   public synchronized boolean isClear(){
         return count==0;    

    }
   }

Stan jest TYLKO w instancji.

Tak więc singleton może zostać później zmodyfikowany, aby wykonać pulę, wystąpienia lokalne wątku itp. I żaden z już napisanych kodów nie musi być zmieniany, aby uzyskać korzyści.

public static class LessUgly {
       private static Hashtable<String,LessUgly> session;
       private static FIFO<LessUgly> freePool = new FIFO<LessUgly>();
       private static final POOL_SIZE=5;
       private int count;

       private LessUgly(){
       }

       public static synchronized getInstance(){
         if( session==null){
            session = new Hashtable<String,LessUgly>(POOL_SIZE);
            for( int i=0; i < POOL_SIZE; i++){
               LessUgly instance = new LessUgly();  
               freePool.add( instance)
            }
         }
         LessUgly instance = session.get( Session.getSessionID());
         if( instance == null){
            instance = freePool.read();
         }
         if( instance==null){
             // TODO search sessions for expired ones. Return spares to the freePool. 
             //FIXME took too long to write example in blog editor.
         }
         return instance;
       }     

Możliwe jest zrobienie czegoś podobnego z klasą statyczną, ale w pośrednim wysyłaniu będzie narzut na wywołanie.

Możesz pobrać instancję i przekazać ją do funkcji jako argument. Pozwala to na przekierowanie kodu do „właściwego” singletona. Wiemy, że będziesz potrzebować tylko jednego ... dopóki tego nie zrobisz.

Dużą zaletą jest to, że stanowe singletony mogą być bezpieczne dla wątków, podczas gdy statyczna klasa nie może, chyba że zmodyfikujesz ją tak, aby była tajnym singletonem.

Tim Williscroft
źródło
4

Pomyśl o singletonie jak o usłudze. Jest to obiekt, który zapewnia określony zestaw funkcjonalności. Na przykład

ObjectFactory.getInstance().makeObject();

Fabryka obiektów to obiekt, który wykonuje określoną usługę.

Z kolei klasa pełna metod statycznych to zbiór działań, które możesz chcieć wykonać, zorganizowanych w powiązaną grupę (Klasa). Na przykład

StringUtils.reverseString("Hello");
StringUtils.concat("Hello", "World");

Przykład StringUtils tutaj to zbiór funkcji, które można zastosować w dowolnym miejscu. Pojedynczy obiekt fabryki to szczególny typ obiektu z wyraźną odpowiedzialnością, który można tworzyć i przekazywać w razie potrzeby.

izb
źródło
4

Instancje klas statycznych są tworzone w czasie wykonywania. Może to zająć dużo czasu. Wystąpienie singletonów można utworzyć tylko w razie potrzeby.

dmo
źródło
13
Singletony są również tworzone w czasie wykonywania ...
rekurencyjne
1
@recursive: można kontrolować wystąpienie Singletona.
Nikit Batale
3
być może lepszym słowem byłaby inicjalizacja (zamiast tworzenia instancji)
Marlon
3

Nie należy używać singletonów w taki sam sposób, jak klas statycznych. W istocie

MyStaticClass.GetInstance().DoSomething();

jest zasadniczo taki sam jak

MyStaticClass.DoSomething();

W rzeczywistości powinieneś traktować singletona jako kolejny obiekt . Jeśli usługa wymaga wystąpienia typu singleton, przekaż to wystąpienie w konstruktorze:

var svc = new MyComplexServce(MyStaticClass.GetInstance());

Usługa nie powinna być świadoma, że ​​obiekt jest singletonem i powinna traktować obiekt tylko jako obiekt.

Obiekt z pewnością można zaimplementować, jako szczegół implementacji i jako aspekt ogólnej konfiguracji, jako singleton, jeśli to ułatwia. Ale rzeczy, które używają obiektu, nie powinny wiedzieć, czy obiekt jest singletonem, czy nie.

yfeldblum
źródło
2

Jeśli przez „klasę statyczną” masz na myśli klasę, która ma tylko zmienne statyczne, to faktycznie mogą one utrzymywać stan. Rozumiem, że jedyną różnicą byłby sposób dostępu do tej rzeczy. Na przykład:

MySingleton().getInstance().doSomething();

przeciw

MySingleton.doSomething();

Elementy wewnętrzne MySingleton będą oczywiście różne między nimi, ale pomijając kwestie bezpieczeństwa wątków, oba będą działać tak samo w odniesieniu do kodu klienta.

Wyjęty spod prawa programista
źródło
2
Singletony same są obiektami -> można je przekazywać jako argumenty.
Christian Klauser
2

Wzorzec singleton jest zwykle używany do obsługi danych niezależnych lub statycznych, w przypadku których wiele wątków może uzyskiwać dostęp do danych w tym samym czasie. Jednym z przykładów mogą być kody stanów.

Mayank
źródło
1

Nigdy nie należy używać singletonów (chyba że uznajesz klasę bez stanu mutowalnego za singleton). „Klasy statyczne” nie powinny mieć żadnego zmiennego stanu, z wyjątkiem być może pamięci podręcznych bezpiecznych dla wątków i tym podobnych.

Prawie każdy przykład singletona pokazuje, jak tego nie robić.

Tom Hawtin - haczyk
źródło
4
A co z klasami menedżerów kontrolującymi zasoby sprzętowe? A co z klasami plików dziennika?
RJFalconer,
0

Jeśli singleton jest czymś, czego możesz się pozbyć, aby po nim posprzątać, możesz go rozważyć, gdy jest to ograniczony zasób (tj. Tylko 1 z nich), którego nie potrzebujesz przez cały czas i masz jakąś pamięć lub koszt zasobów, gdy jest przydzielony.

Kod czyszczenia wygląda bardziej naturalnie, gdy masz singleton, w przeciwieństwie do klasy statycznej zawierającej statyczne pola stanu.

Kod będzie jednak wyglądał tak samo w obu przypadkach, więc jeśli masz bardziej szczegółowe powody, by zapytać, być może powinieneś to rozwinąć.

Lasse V. Karlsen
źródło
0

Oba mogą być całkiem podobne, ale pamiętaj, że prawdziwy Singleton musi sam zostać utworzony (raz przyznany), a następnie obsłużony. Klasa bazy danych PHP, która zwraca instancjęmysqli nie jest tak naprawdę Singletonem (jak niektórzy ją nazywają), ponieważ zwraca instancję innej klasy, a nie instancję klasy, której instancja jest statycznym składnikiem.

Tak więc, jeśli piszesz nową klasę, dla której planujesz zezwolić tylko na jedną instancję w swoim kodzie, równie dobrze możesz napisać ją jako singleton. Pomyśl o tym jak o napisaniu zwykłej klasy i dodaniu do niej, aby ułatwić spełnienie wymagania pojedynczej instancji. Jeśli używasz cudzej klasy, której nie możesz modyfikować (np. mysqli), Powinieneś używać klasy statycznej (nawet jeśli nie uda ci się poprzedzić jej definicji słowem kluczowym).

Brian Warshaw
źródło
0

Singletony są bardziej elastyczne, co może być przydatne w przypadkach, gdy chcesz, aby metoda Instance zwracała różne konkretne podklasy typu Singleton w oparciu o pewien kontekst.

Newdayrising
źródło
0

Klasy statyczne nie mogą być przekazywane jako argumenty; instancje singletona mogą być. Jak wspomniano w innych odpowiedziach, zwróć uwagę na problemy z wątkami w klasach statycznych.

rp

rp.
źródło
0

Singleton może mieć konstruktor i destruktor. W zależności od języka, konstruktor może być wywoływany automatycznie przy pierwszym użyciu singletona lub nigdy, jeśli singleton w ogóle nie jest używany. Klasa statyczna nie miałaby takiej automatycznej inicjalizacji.

Po uzyskaniu odniesienia do pojedynczego obiektu można go używać tak jak każdego innego obiektu. Kod klienta może nawet nie potrzebować wiedzieć, że używa singletona, jeśli odwołanie do singletona jest zapisane wcześniej:

Foo foo = Foo.getInstance();
doSomeWork(foo); // doSomeWork wont even know Foo is a singleton

To oczywiście ułatwia sprawę, gdy zdecydujesz się porzucić wzór Singleton na rzecz prawdziwego wzoru, takiego jak IoC.

Landon Kuhn
źródło
0

Użyj wzorca singleton, gdy musisz obliczyć coś w czasie wykonywania, co gdybyś mógł obliczyć w czasie kompilacji, na przykład tabele odnośników.

Jared Updike
źródło
0

Myślę, że miejsce, w którym Singleton będzie miał więcej sensu niż klasa statyczna, jest wtedy, gdy musisz zbudować pulę kosztownych zasobów (takich jak połączenia z bazą danych). Nie byłbyś zainteresowany tworzeniem puli, gdyby nikt nigdy ich nie używał (klasa statyczna oznacza, że ​​wykonujesz kosztowną pracę, gdy klasa jest ładowana).

Jagmal
źródło
0

Singleton jest również dobrym pomysłem, jeśli chcesz wymusić wydajne buforowanie danych. na przykład mam klasę, która wyszukuje definicje w dokumencie xml. Ponieważ analiza dokumentu może trochę potrwać, skonfigurowałem pamięć podręczną definicji (używam SoftReferences, aby uniknąć outOfmemeoryErrors). Jeśli pożądanej definicji nie ma w pamięci podręcznej, wykonuję kosztowne analizowanie XML. W przeciwnym razie zwracam kopię z pamięci podręcznej. Ponieważ posiadanie wielu pamięci podręcznych oznaczałoby, że nadal może być konieczne wielokrotne ładowanie tej samej definicji, potrzebuję statycznej pamięci podręcznej. Zdecydowałem się zaimplementować tę klasę jako singleton, aby móc napisać klasę tylko przy użyciu zwykłych (niestatycznych) elementów członkowskich danych. Dzięki temu mogę nadal tworzyć analizę klasy, jeśli z jakiegoś powodu będę jej potrzebować (serializacja, testy jednostkowe itp.)

KitsuneYMG
źródło
0

Singleton jest jak usługa, jak już wspomniano. Pro to jego elastyczność. Statyczne, potrzebujesz trochę statycznych części, aby zaimplementować Singleton.

Singleton ma kod, który zajmuje się tworzeniem instancji rzeczywistego obiektu, co może być bardzo pomocne, jeśli napotkasz problemy z wyścigami. W rozwiązaniu statycznym może być konieczne rozwiązanie problemów związanych z wyścigami w wielu lokalizacjach kodu.

Jednak tak samo jak Singleton można skonstruować z niektórymi zmiennymi statycznymi, możesz porównać go z „goto”. Może być bardzo przydatne do budowania innych konstrukcji, ale naprawdę musisz wiedzieć, jak z niego korzystać i nie należy go „nadużywać”. Dlatego generalnie zaleca się trzymanie się Singletona i używanie statycznego, jeśli trzeba.

sprawdź też inny post: Po co wybierać klasę statyczną zamiast implementacji singletona?

Amegon
źródło
0

odnieś to

Podsumowanie:

za. Jedną z prostych praktycznych zasad, których możesz się kierować, jest to, że jeśli nie ma potrzeby utrzymywania stanu, możesz użyć klasy Static, w przeciwnym razie powinieneś użyć klasy Singleton.

b. użyj Singletona, jeśli jest to szczególnie „ciężki” przedmiot. Jeśli twój obiekt jest duży i zajmuje rozsądną ilość pamięci, wiele wywołań n / w (pula połączeń) ... itd. Aby upewnić się, że jego wystąpienie nie zostanie utworzone wiele razy. Klasa Singleton pomoże zapobiec takim przypadkom w przyszłości

Santh
źródło
-1

Kiedy jedna klasa potrzebuje stanu. Singletony utrzymują stan globalny, klasy statyczne nie.

Na przykład, tworzenie pomocnika wokół klasy rejestru: Jeśli masz zmienną gałąź (HKey Current User vs HKEY Local Machine), możesz:

RegistryEditor editor = RegistryEditor.GetInstance();
editor.Hive = LocalMachine

Teraz wszelkie dalsze wywołania tego singletona będą działać w gałęzi komputera lokalnego. W przeciwnym razie, używając klasy statycznej, musisz określić tę gałąź Everytiem komputera lokalnego lub mieć metodę taką jak ReadSubkeyFromLocalMachine.

David J. Sokol
źródło
1
Sprzeciwiłbym się używaniu Singletona w ten sposób ... Bardzo niebezpieczne jest utrzymywanie stanów, ponieważ następny wywołujący może zapomnieć o ustawieniu gałęzi i zapisać do rejestru w niewłaściwej gałęzi ... :-( To jest prawdopodobnie przykład nadużycia, które sprawia, że ​​ludzie myślą, że Singletony są złe.