2016-11-01 2 views
0

Was ist die ordnungsgemäße Verwendung eines Singleton, das eine statische synchronisierte getInstance-Methode verwendet und warum?Korrekte Verwendung von Singleton getInstance-Methode

Zum Beispiel:

MySingleton mySingleton = MySingleton.getInstance(); 
..... 
mySingleton.doSomething(); 

wo mySingleton ein Feld und in der gesamten Klasse verwendet werden würde.

gegen

MySingleton.getInstance().doSomething(); 

EDIT: Durch die richtige, ich meine Codierung Stil und Thread-Sicherheit.

+1

Im Idealfall würden Sie kein Singleton verwenden. Wenn es sein muss, verwende ich lieber eine 'enum', in diesem Fall würde ich' MySingleton.INSTANCE.doSomething() 'schreiben. –

+1

Diese beiden Beispiele sind identisch, obwohl @PeterLawrey Recht hat, enums für Singletons zu empfehlen. –

+0

Definieren Sie "richtig" - was genau fragen Sie? Es ist identisch anders als im ersten Beispiel, Sie erhalten die Instanz und verwenden sie später. –

Antwort

1

Während ich der Antwort von Andy Turner zustimme, Singletons zu vermeiden, wenn möglich, füge ich das der Vollständigkeit halber hinzu: Die statisch synchronisierte getInstance-Methode ist ein Relikt aus der Vergangenheit. Es gibt mindestens 3 Singleton-Musterimplementierungen, die dies nicht erfordern.

a) eifrig Singletons

public class EagerSingleton{ 
    private EagerSingleton(){} 
    private static final EagerSingleton INSTANCE = new EagerSingleton(); 
    public static EagerSingleton getInstance(){ return INSTANCE; } 
} 

Diese Klasse bei Lastzeit initialisiert wird, wann immer die Klasse EagerSingleton in irgendeiner Weise Referenz (beispielsweise durch eine Variable dieses Typs erklärt).

b) faul Singletons

public class LazySingleton{ 
    private LazySingleton(){} 
    private static class Holder{ 
     private static final LazySingleton INSTANCE = new LazySingleton(); 
    } 
    public static LazySingleton getInstance(){ return Holder.INSTANCE; } 

} 

Diese bei Anrufzeit initialisiert wird, (das erste Mal, wenn Sie die Methode getInstance nennen). Der Klassenlader lädt jetzt die Halterklasse und initialisiert das Feld INSTANZ, und dies wird garantiert auf eine synchronisierte Art und Weise durchgeführt. Verwenden Sie diese Version, wenn Ihr Singleton teuer eingerichtet ist und nicht immer notwendig ist.

c) Enum Singleton

public enum EnumSingleton{ 
    INSTANCE; 

    // and if you want, you can add the method, too, but it's 
    // unnecessary: 
    public static EnumSingleton getInstance(){ return INSTANCE; } 
} 

Enum-Artikel sind Kompilierung-Konstanten, dh ihre Einzigartigkeit zur Compile-Zeit garantiert ist, nicht nur zur Laufzeit (zur Laufzeit, ist Singletons einzigartige pro Class Loader, und dass gilt für alle Versionen). Dies ist der beste Weg zu gehen, es sei denn, Ihre Anforderungen sind von einer bestehenden Klasse zu erweitern.

Die Enum-Version gibt Ihnen viele andere Funktionen kostenlos:

  • gleich/hashCode/toString Implementierungen aus der Box
  • Verteidigung gegen Deserialisierung Angriffe
  • Multiton-Unterstützung (fügen Sie einfach einen weiteren Aufzählungs Artikel)

Also das nächste Mal, wenn Sie jemand die doppelt überprüft Verriegelung oder ähnliches schreiben sehen, ihnen sagt, sie sind viel zu kompliziert und Technik al. Lassen Sie den Klassenlader die Arbeit für Sie erledigen.

Mit allen 3 Versionen: Stellen Sie sicher, dass die von Ihnen verwendete Funktionalität durch eine Schnittstelle und Code für diese Schnittstelle und nicht den Implementierungstyp unterstützt wird. Dadurch wird Ihr Code testbar.

0

Ich denke, es wäre besser, ein Feld für jedes Singleton in der Klasse zu definieren. So können Sie leicht Abhängigkeiten einer Klasse zu Singletons im System herausfinden, indem Sie einfach auf die ersten n Zeilen schauen. Es hilft, die Kopplung einer Klasse zu verstehen.

Auch das Definieren von Feldern für Singletons erleichtert das Testen. Wenn Sie zufällig Methoden des Singleton auf eine Schnittstelle verschieben können, können Sie eine Stub-Klasse für den Singleton definieren und Sie können Stub Singleton in Ihren Testcode injizieren.

Wenn Ihr Singleton Thread-sicher ist, sollte es kein Problem geben.

1

Eine bessere Lösung als ein Singleton verwenden ist dependency injection zu verwenden:

class MyClass { 
    private final MySingleton mySingleton; 

    MyClass(MySingleton mySingleton) { 
    this.mySingleton = mySingleton; 
    } 

    // Use mySingleton in instance methods as required. 
} 

Der Vorteil hierbei ist, dass die Tatsache, dass es ein Singleton ist nicht relevant ist - es ein Singleton sein kann, aber es doesn‘ t muss sein.

Ich nannte das Feld mySingleton weil das ist, was Sie es in Ihrer Frage genannt haben, aber es gibt nicht mehr eine Voraussetzung dafür, wirklich Singleton zu sein: die einzige Sache ist, dass MyClass nicht über das Leben kümmern muss Zyklus der Instanz.

Dies bricht die statische Kopplung zwischen MyClass und MySingleton, die vorhanden wäre, wenn Sie es durch eine der in der Frage beschriebenen Möglichkeiten getan haben. Dies macht es unter anderem einfacher, MyClass zu testen.

+0

Ich stimme zu, wir dürfen Singletons nicht missbrauchen. Jetzt benötigt DI einen Abhängigkeitscontainer und ein Singleton nicht. Wenn Sie einen Abhängigkeitscontainer verwenden oder wenn Sie das verwenden möchten, ist die Idee gut, aber wenn Sie das nicht benötigen und Sie 3 oder 4 klassische Singletons in Ihrem Projekt haben, warum diesen Overhead hinzufügen? Testen eines Singleton ist schwieriger als DI, aber mit Reflexion ist es sehr spielbar. – davidxxx

0

Jemand muss ein Singleton instanziieren. Dies muss nur einmal gemacht werden. Hier kommt thread safty ins Spiel. Wenn es eine Chance ist, dass verschiedene Themen

SingletonClass.getInstance(); 

fast zur gleichen Zeit nennen, hat die Instanziierung des Singletons wie diese geschützt werden:

private static volatile SingletonClass myInstance; 

public static SingletonClass getInstance() 
{ 
    if (myInstance == null) 
    { 
     synchronized(SingletonClass.class) 
     { 
      if (myInstance == null) 
      { 
       myInstance = new SingletonClass(); 
      } 
     } 
    } 

    return myInstance; 
} 

Dies wird als „doppelt geprüft Verriegelung“ bezeichnet. Die Variable muss flüchtig sein.

Wenn die Methoden der SingletonClass den Status zwischen Threads teilen (z. B. ein Element, das von einem Thread geschrieben und von einem anderen Thread gelesen wird), muss bei der Synchronisierung besondere Sorgfalt angewendet werden. Aber das ist normal und hat nichts mit dem Singleton-Muster zu tun.

Ihre Frage was ist der Unterschied zwischen "XY.getInstance(). DoSomething()" vs. eine Referenz in einem eigenen Mitglied für den späteren Zugriff behalten: Es ist nur eine (geringfügige) Leistungseinbuße (Callstack eine mehr, if-Anweisung, zurück).Aber IMO, das ist ignorierbar, denn auf lange Sicht würde der Java-Optimierer das trotzdem inline machen. Auf der anderen Seite: Halten Sie eine Referenz hält den Code kürzer und lesbarer, vor allem, wenn Sie oft auf den Singleton zugreifen. Am Ende ist es Geschmackssache.