design patterns stadt Wann sollten Sie das Singleton-Muster anstelle einer statischen Klasse verwenden?




singleton uml (18)

Die beiden können sehr ähnlich sein, aber denken Sie daran, dass der wahre Singleton selbst instanziiert (einmal vergeben) und dann bedient werden muss. Eine PHP-Datenbankklasse, die eine Instanz von mysqli ist nicht wirklich ein Singleton (wie manche Leute es nennen), weil 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, der Sie nur eine Instanz in Ihrem Code erlauben möchten, können Sie sie auch als Singleton schreiben. Stellen Sie sich das so vor, als würden Sie eine Klasse für "jane-jane" schreiben und sie hinzufügen, um die Anforderungen für die Einzelinstanziierung zu vereinfachen. Wenn Sie die Klasse einer anderen Person verwenden, die Sie nicht ändern können (wie mysqli ), sollten Sie eine statische Klasse verwenden (auch wenn Sie ihrer Definition nicht das Schlüsselwort voranstellen).

Benennen Sie die Entwurfsüberlegungen bei der Entscheidung zwischen der Verwendung eines singleton und einer statischen Klasse. Wenn du dies tust, bist du gezwungen, die beiden zu kontrastieren, also sind alle Kontraste, die du dir vorstellen kannst, auch nützlich, um deinen Denkprozess zu zeigen! Außerdem mag jeder Interviewer gerne illustrative Beispiele. :)


Wenn die einzelne Klasse Status benötigt. Singletons erhalten einen globalen Zustand, statische Klassen nicht.

Zum Beispiel, einen Helper um eine Registrierungsklasse herum zu machen: Wenn Sie eine änderbare Struktur haben (HKey Current User vs. HKEY Local Machine), könnten Sie gehen:

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

Jetzt werden alle weiteren Aufrufe dieses Singletons in der lokalen Maschinenstruktur ausgeführt. Andernfalls müssten Sie bei Verwendung einer statischen Klasse angeben, dass die Datei "Local Machine" auf jeder Ebene liegt, oder über eine Methode wie " ReadSubkeyFromLocalMachine .


Ich denke, ein Ort, an dem Singleton mehr Sinn macht als die statische Klasse, ist, wenn Sie einen Pool teurer Ressourcen (wie Datenbankverbindungen) aufbauen müssen. Sie wären nicht daran interessiert, den Pool zu erstellen, wenn Sie ihn nie benutzen würden (statische Klasse bedeutet, dass Sie die teure Arbeit machen, wenn die Klasse geladen wird).


Singleton ist wie ein Service, wie bereits erwähnt. Pro ist seine Flexibilität. Statisch, nun, Sie brauchen einige statische Teile, um Singleton zu implementieren.

Singleton hat einen Code, der für die Instanziierung des eigentlichen Objekts sorgt, was eine große Hilfe sein kann, wenn Sie Rennprobleme bekommen. In einer statischen Lösung müssen Sie möglicherweise mit Rennproblemen an mehreren Codestellen umgehen.

Wie auch Singleton mit einigen statischen Variablen konstruiert werden kann, können Sie es 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 es nicht "überbeanspruchen" sollte. Daher empfiehlt es sich, bei Singleton zu bleiben und bei Bedarf auch statisch zu bleiben.

Überprüfen Sie auch den anderen Beitrag: Warum wählen Sie eine statische Klasse über eine Singleton-Implementierung?


Singletons sollten niemals verwendet werden (es sei denn, Sie betrachten eine Klasse ohne veränderlichen Zustand als Singleton). "Statische Klassen" sollten keinen änderbaren Zustand haben, abgesehen von thread-sicheren Caches und dergleichen.

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


Verweise codeofdoom.com/wordpress/2008/04/20/…

Zusammenfassung:

ein. Eine einfache Faustregel, der Sie folgen können, ist, wenn Sie den Zustand nicht beibehalten müssen, können Sie eine statische Klasse verwenden, andernfalls sollten Sie ein Singleton verwenden.

b. Verwenden Sie ein Singleton, wenn es sich um ein besonders "schweres" Objekt handelt. Wenn Ihr Objekt groß ist und eine angemessene Menge an Arbeitsspeicher belegt, viele N / W-Aufrufe (Verbindungspool) ..etc. Um sicherzustellen, dass es nicht mehrfach instanziiert wird. Eine Singleton-Klasse wird dazu beitragen, einen solchen Fall zu verhindern


Wenn Sie mit "statische Klasse" eine Klasse meinen, die nur statische Variablen hat, können sie tatsächlich den Zustand beibehalten. Mein Verständnis ist, dass der einzige Unterschied sein würde, wie Sie auf dieses Ding zugreifen. Beispielsweise:

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

gegen

MySingleton.doSomething();

Die Interna von MySingleton werden sich natürlich unterscheiden, aber abgesehen von Thread-Sicherheitsfragen werden beide dasselbe in Bezug auf den Client-Code tun.


Eine meiner Lieblingsdiskussionen über dieses Problem ist here (ursprüngliche Seite unten, jetzt verbunden mit Internet Archive Wayback Machine .)

Um die Flexibilitätsvorteile eines Singleton zusammenzufassen:

  • Ein Singleton kann leicht in eine Fabrik umgewandelt werden
  • Ein Singleton kann leicht modifiziert werden, um verschiedene Unterklassen zurückzugeben
  • Dies kann zu einer wartungsfreundlicheren Anwendung führen

  • Singletons können Schnittstellen implementieren und von anderen Klassen erben.
  • Singletons können faul geladen werden. Nur wenn es wirklich benötigt wird. Das ist sehr praktisch, wenn die Initialisierung teure Ressourcenladungen oder Datenbankverbindungen beinhaltet.
  • Singletons bieten ein echtes Objekt.
  • Singletons können zu einer Fabrik erweitert werden. Das Objektmanagement hinter den Kulissen ist abstrakt, so dass es besser wartbar ist und zu besserem Code führt.

Statische Klassen können nicht als Argumente übergeben werden; Instanzen eines Singleton können sein. Wie in anderen Antworten erwähnt, achten Sie auf Threading-Probleme mit statischen Klassen.

rp


Wenn ein Singleton etwas ist, über das man verfügen kann, um danach aufzuräumen, kann man es in Betracht ziehen, wenn es eine begrenzte Ressource (dh nur eine davon) ist, die man nicht ständig braucht und irgendeine Art von Speicher oder Ressourcenkosten, wenn sie zugewiesen werden.

Der Bereinigungscode sieht natürlicher aus, wenn Sie einen Singleton haben, im Gegensatz zu einer statischen Klasse, die statische Statusfelder enthält.

Der Code wird jedoch in beiden Fällen gleich aussehen. Wenn Sie also genauere Gründe für Ihre Fragen haben, sollten Sie das vielleicht näher ausführen.


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

  • Kann den globalen Staat einführen
  • Eng mit mehreren anderen Klassen gekoppelt werden
  • Abhängigkeiten ausblenden
  • Kann Einheitentest-Klassen in Isolation schwierig machen

Sehen Sie sich stattdessen die Abhängigkeitsinjektion und Inversion von Control Container- Bibliotheken an. Mehrere der IoC-Bibliotheken werden das Lifetime Management für Sie übernehmen.

(Wie immer gibt es Ausnahmen, z. B. statische Mathematikklassen und C # -Erweiterungsmethoden.)


Eine statische Klasse mit einer Ladung statischer Variablen ist ein bisschen wie 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 Staat ist NUR in der Instanz.

So kann das Singleton später geändert werden, um Pooling, thread-lokale Instanzen usw. zu machen. Und keiner der bereits geschriebenen Codes muss geändert werden, um den Vorteil zu erhalten.

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, etwas Ähnliches mit einer statischen Klasse zu tun, aber es wird einen pro-Aufruf-Overhead im indirekten Versand geben.

Sie können die Instanz abrufen und als Argument an eine Funktion übergeben. Dadurch kann der Code zum "richtigen" Singleton geleitet werden. Wir wissen, dass du nur eins brauchst ... bis du es nicht tust.

Der große Vorteil ist, dass Stateful Singletons threadsicher gemacht werden können, während eine statische Klasse das nicht kann, es sei denn man modifiziert sie zu einem geheimen Singleton.


Singletons sollten nicht wie statische Klassen verwendet werden. Im Grunde genommen,

MyStaticClass.GetInstance().DoSomething();

ist im Wesentlichen das Gleiche wie

MyStaticClass.DoSomething();

Was Sie eigentlich tun sollten, ist , das Singleton als ein anderes Objekt zu behandeln . Wenn ein Service eine Instanz des Singletontyps benötigt, übergeben Sie diese Instanz im Konstruktor:

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

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

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


Ein Singleton kann einen Konstruktor und einen Destruktor haben. Abhängig von Ihrer Sprache kann der Konstruktor automatisch aufgerufen werden, 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 wird, kann es wie jedes andere Objekt verwendet werden. Der Client-Code muss möglicherweise nicht einmal wissen, ob er einen Singleton verwendet, wenn ein Verweis auf den Singleton früher gespeichert wird:

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

Dies macht es offensichtlich einfacher, wenn Sie das Singleton-Muster zugunsten eines echten Musters wie IoC ablehnen.


Verwenden Sie das Singleton-Muster, wenn Sie zur Laufzeit etwas berechnen müssen, das Sie bei der Kompilierung berechnen könnten, wie beispielsweise Nachschlagetabellen.


Ein Singleton ist auch eine gute Idee, wenn Sie ein effizientes Caching von Daten erzwingen möchten. Zum Beispiel habe ich eine Klasse, die Definitionen in einem XML-Dokument nachschlägt. Da das Parsing des Dokuments einige Zeit dauern kann, habe ich einen Cache mit Definitionen eingerichtet (ich verwende SoftReferences, um outOfmemoryErrors zu vermeiden). Wenn die gewünschte Definition nicht im Cache ist, mache ich das teure XML-Parsing. Ansonsten gebe ich eine Kopie aus dem Cache zurück. Da mehrere Caches haben würde ich immer noch die gleiche Definition mehrere Male laden müssen, muss ich einen statischen Cache haben. Ich entschied mich, diese Klasse als Singleton zu implementieren, so dass ich die Klasse nur mit normalen (nicht statischen) Datenmembern schreiben konnte. Dadurch kann ich immer noch eine Beschreibung der Klasse erstellen, wenn ich sie aus irgendeinem Grund brauche (Serialisierung, Komponententest usw.)


Statische Klassen werden zur Laufzeit instanziiert. Dies könnte zeitaufwendig sein. Singletons können nur bei Bedarf instanziiert werden.





design-patterns