Wann sollten Sie das Singleton-Muster anstelle einer statischen Klasse verwenden? [geschlossen]


85

Nennen Sie die Entwurfsüberlegungen bei der Entscheidung zwischen der Verwendung eines Singletons und einer statischen Klasse. Auf diese Weise sind Sie gezwungen, die beiden zu kontrastieren. Welche Kontraste Sie auch finden können, ist auch nützlich, um Ihren Denkprozess zu zeigen! Außerdem sieht jeder Interviewer gerne anschauliche Beispiele. :) :)


Eine Java-Klasse kann nur statisch werden, wenn es sich um eine innere Klasse handelt
Harshana

1
Wenn der Status des Objekts eine Rolle spielt, verwenden Sie Singleton. Andernfalls verwenden Sie eine statische Klasse.
Levent Divilioglu

Antworten:


80
  • Singletons können Schnittstellen implementieren und von anderen Klassen erben.
  • Singletons können faul geladen werden. Nur wenn es tatsächlich gebraucht wird. Dies ist sehr praktisch, wenn die Initialisierung teures Laden von Ressourcen oder Datenbankverbindungen umfasst.
  • Singletons bieten ein tatsächliches Objekt.
  • Singletons können zu einer Fabrik erweitert werden. Die Objektverwaltung hinter den Kulissen ist abstrakt, daher besser wartbar und führt zu besserem Code.

2
Schauen Sie sich auch diesen Link an: codeofdoom.com/wordpress/2008/04/20/…
Amit

4
"Singletons können faul geladen werden" - In C # wird der statische Konstruktor nur aufgerufen, wenn zum ersten Mal auf ein statisches Element verwiesen wird. In PHP können Sie das automatische Laden verwenden, damit es nur bei der ersten Verwendung der Klasse ausgeführt wird.
Mpen

Statische Java-Initialisierungen sind ebenfalls faul. Keine Punkte für Singletons da.
MikeFHay

13

Wie wäre es mit "beides vermeiden"? Singletons und statische Klassen:

  • Kann globalen Staat einführen
  • Verbinde dich eng mit mehreren anderen Klassen
  • Abhängigkeiten ausblenden
  • Kann isolierte Unit-Test-Klassen erschweren

Schauen Sie sich stattdessen Dependency Injection und Inversion von Control Container- Bibliotheken an. Mehrere der IoC-Bibliotheken übernehmen die Lebensdauerverwaltung für Sie.

(Wie immer gibt es Ausnahmen wie statische Mathematikklassen und C # -Erweiterungsmethoden.)


1
Kleine Nissen: Singleton-Klassen sind mit Abhängigkeitsinjektionstechniken kompatibel (fügen Sie sie einfach in ihre abhängigen Klassen ein und sie müssen nichts hartcodieren) - dies ermöglicht das isolierte Verspotten und Testen. Sie sind auch ein gültiges Entwurfsmuster für die Verwaltung von Ressourcen, von denen bekannt ist, dass sie plattformweit begrenzt sind. (Das klassische Beispiel sind Drucker, die kein Konfliktmanagement haben.)
cdleary

@cdleary - vereinbart; Bei der klassischen Implementierung bleibt Singleton.getInstance () jedoch häufig in der gesamten Codebasis. "Singletons" zum Verwalten von Ressourcen, Caches usw. können mit POCOs / POJOs und IoC-Container-Frameworks implementiert werden, die die Lebensdauerverwaltung unterstützen (registrieren Sie den Typ als Containerlebensdauer, und jede Auflösung erhält dieselbe Instanz).
TrueWill

9
Wenn Sie Ihren Singletons eine angemessene Beerdigung geben möchten, gehen Sie zu singletonfuneralservice.com
TrueWill

1
Hide Dependencieskleine Seiteninfo zu diesem Punkt: Sie können das Inversion of Control-Muster beispielsweise mithilfe von Ninject implementieren . Auf diese Weise können Sie nur eine Instanz eines Typs verwenden, indem Sie ihn an a binden. Dies SingletonScopebedeutet, dass immer dieselbe Instanz injiziert wird, die Klasse jedoch kein Singleton ist.
LuckyLikey

8

Ich würde behaupten, der einzige Unterschied ist die Syntax: MySingleton.Current.Whatever () vs MySingleton.Whatever (). Der Staat ist, wie David erwähnte, in beiden Fällen letztendlich "statisch".


EDIT: Die Beerdigungsbrigade kam von Digg ... jedenfalls dachte ich an einen Fall, der einen Singleton erfordern würde. Statische Klassen können weder von einer Basisklasse erben noch eine Schnittstelle implementieren (zumindest in .NET können sie dies nicht). Wenn Sie diese Funktionalität benötigen, müssen Sie einen Singleton verwenden.


7

Eine meiner Lieblingsdiskussionen zu diesem Thema ist hier (ursprüngliche Website nicht verfügbar, jetzt mit Internet Archive Wayback Machine verknüpft ).

Um die Flexibilitätsvorteile eines Singleton zusammenzufassen:

  • Ein Singleton kann leicht in eine Fabrik umgewandelt werden
  • Ein Singleton kann leicht geändert werden, um verschiedene Unterklassen zurückzugeben
  • Dies kann zu einer wartbareren Anwendung führen

5

Eine statische Klasse mit einer Menge statischer Variablen ist ein 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;    

    }
   }

Ein Singleton mit einer tatsächlichen Instanz ist besser.

/**
 * 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;    

    }
   }

Der Status befindet sich NUR in der Instanz.

So kann der Singleton später geändert werden, um Pooling, threadlokale Instanzen usw. durchzuführen. Und keiner der bereits geschriebenen Codes muss geändert werden, um den Vorteil zu erzielen.

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;
       }     

Es ist möglich, mit einer statischen Klasse etwas Ähnliches zu tun, aber der indirekte Versand verursacht einen Overhead pro Anruf.

Sie können die Instanz abrufen und als Argument an eine Funktion übergeben. Dadurch kann der Code an den "richtigen" Singleton gerichtet werden. Wir wissen, dass Sie nur eines davon brauchen ... bis Sie es nicht tun.

Der große Vorteil besteht darin, dass zustandsbehaftete Singletons threadsicher gemacht werden können, während eine statische Klasse dies nicht kann, es sei denn, Sie ändern sie als geheimen Singleton.


4

Stellen Sie sich einen Singleton wie einen Dienst vor. Es ist ein Objekt, das eine bestimmte Reihe von Funktionen bietet. Z.B

ObjectFactory.getInstance().makeObject();

Die Objektfactory ist ein Objekt, das einen bestimmten Dienst ausführt.

Im Gegensatz dazu ist eine Klasse voller statischer Methoden eine Sammlung von Aktionen, die Sie möglicherweise ausführen möchten, organisiert in einer verwandten Gruppe (Die Klasse). Z.B

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

Das StringUtils-Beispiel hier ist eine Sammlung von Funktionen, die überall angewendet werden können. Das Singleton-Factory-Objekt ist ein bestimmter Objekttyp mit einer eindeutigen Verantwortung, der bei Bedarf erstellt und weitergegeben werden kann.


4

Statische Klassen werden zur Laufzeit instanziiert. Dies kann zeitaufwändig sein. Singletons können nur bei Bedarf instanziiert werden.


13
Singletons werden auch zur Laufzeit instanziiert ...
rekursiv

1
@recursive: Die Singleton-Instanziierung kann gesteuert werden.
Nikit Batale

3
Vielleicht wäre ein besseres Wort die Initialisierung (anstatt die Instanziierung)
Marlon

3

Singletons sollten nicht wie statische Klassen verwendet werden. Im Wesentlichen

MyStaticClass.GetInstance().DoSomething();

ist im Wesentlichen das gleiche wie

MyStaticClass.DoSomething();

Was Sie eigentlich tun sollten, ist , den Singleton als ein weiteres Objekt zu behandeln . Wenn für einen Dienst eine Instanz vom Typ Singleton erforderlich ist, übergeben Sie diese Instanz im Konstruktor:

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

Der Dienst sollte nicht wissen, dass das Objekt ein Singleton ist, und das Objekt nur als Objekt behandeln.

Das Objekt kann sicherlich als Implementierungsdetail und als Aspekt der Gesamtkonfiguration als Singleton implementiert werden, wenn dies die Dinge einfacher macht. Die Dinge, die das Objekt verwenden, sollten jedoch nicht wissen müssen, ob das Objekt ein Singleton ist oder nicht.


2

Wenn mit "statische Klasse" eine Klasse gemeint ist, die nur statische Variablen enthält, können sie tatsächlich den Status beibehalten. Mein Verständnis ist, dass der einzige Unterschied darin besteht, wie Sie auf dieses Ding zugreifen. Beispielsweise:

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

gegen

MySingleton.doSomething();

Die Interna von MySingleton unterscheiden sich offensichtlich zwischen ihnen, aber abgesehen von Thread-Sicherheitsproblemen werden beide hinsichtlich des Client-Codes die gleiche Leistung erbringen.


2
Singletons sind selbst Objekte -> sie können als Argumente übergeben werden.
Christian Klauser

2

Das Singleton-Muster wird im Allgemeinen verwendet, um instanzunabhängige oder statische Daten zu bedienen, bei denen mehrere Threads gleichzeitig auf Daten zugreifen können. Ein Beispiel können Statuscodes sein.


1

Singletons sollten niemals verwendet werden (es sei denn, Sie betrachten eine Klasse ohne veränderlichen Status als Singleton). "statische Klassen" sollten keinen veränderlichen Zustand haben, außer vielleicht threadsicheren Caches und dergleichen.

So ziemlich jedes Beispiel eines Singletons zeigt, wie man es nicht macht.


4
Was ist mit Managerklassen, die Hardwareressourcen steuern? Was ist mit Protokolldateiklassen?
RJFalconer

0

Wenn Sie über einen Singleton verfügen können, um ihn zu bereinigen, können Sie ihn in Betracht ziehen, wenn es sich um eine begrenzte Ressource handelt (dh nur eine davon), die Sie nicht ständig benötigen und über eine Art Speicher verfügen oder Ressourcenkosten, wenn es zugewiesen wird.

Der Bereinigungscode sieht natürlicher aus, wenn Sie einen Singleton haben, als eine statische Klasse, die statische Statusfelder enthält.

Der Code sieht jedoch in beiden Fällen ähnlich aus. Wenn Sie also spezifischere Gründe für die Frage haben, sollten Sie dies vielleicht näher erläutern.


0

Die beiden können sehr ähnlich sein, aber denken Sie daran, dass der wahre Singleton selbst instanziiert (einmal gewährt) und dann bedient werden muss. Eine PHP-Datenbankklasse, die eine Instanz von zurückgibt, mysqliist nicht wirklich ein Singleton (wie manche Leute es nennen), da sie eine Instanz einer anderen Klasse zurückgibt , keine Instanz der Klasse, die die Instanz als statisches Mitglied hat.

Wenn Sie also eine neue Klasse schreiben, von der Sie nur eine Instanz in Ihrem Code zulassen möchten, können Sie sie auch als Singleton schreiben. Stellen Sie sich vor, Sie schreiben eine einfache Jane-Klasse und fügen sie hinzu, um die Anforderung der Einzelinstanziierung zu vereinfachen. Wenn Sie eine andere Klasse verwenden, die Sie nicht ändern können (wie mysqli), sollten Sie eine statische Klasse verwenden (auch wenn Sie der Definition nicht das Schlüsselwort voranstellen).


0

Singletons sind flexibler, was in Fällen nützlich sein kann, in denen die Instanzmethode je nach Kontext verschiedene konkrete Unterklassen des Singleton-Typs zurückgeben soll.


0

Statische Klassen können nicht als Argumente weitergegeben werden. Instanzen eines Singleton können sein. Achten Sie, wie in anderen Antworten erwähnt, auf Threading-Probleme mit statischen Klassen.

rp


0

Ein Singleton kann einen Konstruktor und einen Destruktor haben. Abhängig von Ihrer Sprache wird der Konstruktor möglicherweise automatisch aufgerufen, wenn Ihr Singleton zum ersten Mal verwendet wird, oder niemals, wenn Ihr Singleton überhaupt nicht verwendet wird. Eine statische Klasse hätte keine solche automatische Initialisierung.

Sobald ein Verweis auf ein Singleton-Objekt erhalten wurde, kann es wie jedes andere Objekt verwendet werden. Der Client-Code muss möglicherweise nicht einmal wissen, dass er einen Singleton verwendet, wenn ein Verweis auf den Singleton früher gespeichert wurde:

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

Dies erleichtert natürlich die Arbeit, wenn Sie das Singleton-Muster zugunsten eines echten Musters wie IoC ablegen.


0

Verwenden Sie das Singleton-Muster, wenn Sie zur Laufzeit etwas berechnen müssen, das Sie zur Kompilierungszeit berechnen würden, wenn Sie könnten, z. B. Nachschlagetabellen.


0

Ich denke, ein Ort, an dem Singleton sinnvoller ist als die statische Klasse, ist, wenn Sie einen Pool kostspieliger Ressourcen (wie Datenbankverbindungen) erstellen müssen. Sie wären nicht daran interessiert, den Pool zu erstellen, wenn niemand sie jemals verwendet (statische Klasse bedeutet, dass Sie die kostspielige Arbeit erledigen, wenn die Klasse geladen wird).


0

Ein Singleton ist auch eine gute Idee, wenn Sie ein effizientes Zwischenspeichern von Daten erzwingen möchten. Zum Beispiel habe ich eine Klasse, die Definitionen in einem XML-Dokument nachschlägt. Da das Parsen des Dokuments eine Weile dauern kann, habe ich einen Cache mit Definitionen eingerichtet (ich verwende SoftReferences, um outOfmemeoryErrors zu vermeiden). Wenn sich die gewünschte Definition nicht im Cache befindet, mache ich das teure XML-Parsing. Ansonsten gebe ich eine Kopie aus dem Cache zurück. Da mehrere Caches bedeuten würden, dass ich dieselbe Definition möglicherweise noch mehrmals laden muss, muss ich einen statischen Cache haben. Ich habe mich entschieden, diese Klasse als Singleton zu implementieren, damit ich die Klasse nur mit normalen (nicht statischen) Datenelementen schreiben kann. Auf diese Weise kann ich immer noch eine Istantiation der Klasse erstellen, falls ich sie aus irgendeinem Grund benötige (Serialisierung, Komponententests usw.).


0

Singleton ist wie ein Dienst, wie bereits erwähnt. Pro ist seine Flexibilität. Statisch, nun, Sie benötigen einige statische Teile, um Singleton zu implementieren.

Singleton verfügt über Code, der sich um die Instanziierung des eigentlichen Objekts kümmert. Dies kann eine große Hilfe sein, wenn Sie auf Rennprobleme stoßen. In einer statischen Lösung müssen Sie möglicherweise Rennprobleme an mehreren Codestandorten lösen.

So wie Singleton mit einigen statischen Variablen erstellt werden kann, können Sie es möglicherweise mit 'goto' vergleichen. Es kann sehr nützlich sein, um andere Strukturen zu bauen, aber Sie müssen wirklich wissen, wie man es benutzt und sollten es nicht "überbeanspruchen". Daher wird allgemein empfohlen, sich an Singleton zu halten und bei Bedarf statisch zu verwenden.

Überprüfen Sie auch den anderen Beitrag: Warum sollten Sie eine statische Klasse einer Singleton-Implementierung vorziehen?


0

verweisen Sie dies

Zusammenfassung:

ein. Eine einfache Faustregel, der Sie folgen können, lautet: Wenn der Status nicht beibehalten werden muss, können Sie eine statische Klasse verwenden. Andernfalls sollten Sie einen Singleton verwenden.

b. Verwenden Sie einen Singleton, wenn es sich um ein besonders „schweres“ Objekt handelt. Wenn Ihr Objekt groß ist und eine angemessene Menge an Speicherplatz beansprucht, werden viele n / w-Aufrufe (Verbindungspool) usw. durchgeführt. Um sicherzustellen, dass es nicht mehrmals instanziiert wird. Eine Singleton-Klasse hilft dabei, zu verhindern, dass ein solcher Fall jemals auftritt


-1

Wenn die einzelne Klasse den Status benötigt. Singletons behalten einen globalen Status bei, statische Klassen nicht.

Erstellen eines Hilfsprogramms für eine Registrierungsklasse: Wenn Sie eine veränderbare Struktur haben (HKey Current User vs. HKEY Local Machine), können Sie Folgendes tun:

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

Jetzt werden alle weiteren Aufrufe dieses Singletons auf dem Local Machine Hive ausgeführt. Andernfalls müssten Sie bei Verwendung einer statischen Klasse angeben, dass die lokale Maschine jeden Tag enthält, oder eine Methode wie diese verwenden ReadSubkeyFromLocalMachine.


1
Ich würde gegen die Verwendung eines Singleton auf diese Weise argumentieren ... Es ist sehr gefährlich, die Zustände aufrechtzuerhalten, da der nächste Anrufer möglicherweise vergisst, den Bienenstock festzulegen und in die Registrierung im falschen Bienenstock zu schreiben ... :-( Dies ist wahrscheinlich ein Beispiel für Missbrauch, der die Leute denken lässt, Singletons seien schlecht.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.