OOP Verständnisfrage zu Singelton Pattern

Iago

Mitglied
Hallo,
ich habe eine Frage bezülich des Feldes instanz zu folgendem Code:
Java:
public class Singelton
{
   private static Singelton instanz = null;

   private Singelton() {}

   public static Singelton getInstanz()
   {
      if (instanz == null)
         instanz = new Singelton();

      return instanz;
   }
 }

//in irgendeiner anderen Klasse
Singelton obj1 = Singelton.getInstanz();
Singelton obj2 = Singelton.getInstanz();

Wie kann man das verstehen, dass das Feld instanz von der "Art" Singelton ist. private besagt, dass das Feld nicht öffentlich ist, static, dass es nicht an die Instanziierung eines Objektes gebunden ist, aber wozu dann noch Singelton vor dem Feldnamen?

Danke, Iago
 
Muss man doch bei allen Variablen machen. ???:L

Sehr wichtig:

Java:
if (instanz == null)
    instanz = new Singelton();

So ein Code muss immer synchronisiert werden. Damit du dir das aber erspaarst kannst du einen static constructor anlegen und in dem die Variable setzen.
 
static Konstruktor? Nee.. 😉

Bei diesem Beispiel kann er auch einfach komplett auf das Lazyinit und dadurch auch auf synchronisation verzichten:
Java:
public class Singelton
{
   private static Singelton instanz = new Singleton();
 
   private Singelton() {}
 
   public static Singelton getInstanz()
   {
      return instanz;
   }
 }
.. und eigentlich auf die Methode auch:
Java:
public class Singelton
{
   public final static Singelton INSTANCE = new Singleton();
 
   private Singelton() {}
 
 }

Ansonsten sehe ich das wie Landei, das GoF Singleton hat Konsequenzen.
 
Davon abgesehen das ich Landei und maki natürlich zustimme, das GoF Singleton ist ein Anti-Pattern, ist mir unbegreiflich warum jeder immer meint besonders clever sein müssen mit 'Lazy-Init'.
Java:
if (instanz == null)
    instanz = new Singelton();
Es gibt fast keinen Fall wo dieser Code Vorteile bringt. In allen anderen Fällen führt es zu Problemen mit Threads, führt unnötige Codezeilen ein, INSTANCE kann nicht mehr final sein und dann ist auch noch etwas langsamer. :autsch:
Leider bekomme ich das auch meinen Kollegen nicht eingeimpft.
 
static Konstruktor? Nee.. 😉

Bei diesem Beispiel kann er auch einfach komplett auf das Lazyinit und dadurch auch auf synchronisation verzichten:
Java:
public class Singelton
{
   private static Singelton instanz = new Singleton();
 
   private Singelton() {}
 
   public static Singelton getInstanz()
   {
      return instanz;
   }
 }
.. und eigentlich auf die Methode auch:
Java:
public class Singelton
{
   public final static Singelton INSTANCE = new Singleton();
 
   private Singelton() {}
 
 }

Auf aktuellen JVMs wird die Initialisierung in dem Fall sogar lazy ausgeführt. Klassen werden erst initialisiert wenn das erste mal eine Methode davon aufgerufen wird. Um die synchronization braucht man sich dann auch keine Sorgen machen, die JVM kümmert sich da schon drum.

Java:
public class SingletonTest
{
	public static void main(final String[] args)
	{
		SingletonTest.test(false);
		SingletonTest.test(true);
	}

	public static void test(final boolean b)
	{
		System.out.println("before");
		if (b)
			System.out.println(Singleton.instance);
		System.out.println("after");
		System.out.println();
	}
}

class Singleton
{
	public static Singleton instance = new Singleton();

	private Singleton()
	{
		System.out.println("instance created");
	}
}

Die Instanz von Singleton wird erst beim Aufruf von test(true) erzeugt und nicht vorher.
 
Zuletzt bearbeitet:
Wenn man wirklich ein lazy-loading, thread-safe Singleton haben will, gibt es - so weit ich weiß - nur zwei einfache und wirklich "saubere" Lösungen:

1) Eine statische innere Klasse hält die Referenz:
Java:
public final class Foo {

    private static class FooLoader {
        private static final Foo INSTANCE = new Foo();
    }

    private Foo() {}

    public static Foo getInstance() {
        return FooLoader.INSTANCE;
    }
}

2) Seit Java 1.5 der bevorzugte Stil: Man benutzt ein [c]enum[/c].
Java:
public enum Foo {
   INSTANCE;
}

Achtung, zusätzliche Vorkehrungen sind notwendig, wenn die Singletons serialisiert werden müssen!

Man sieht oft wilde Implementierungen, die mit synchronized und dem double-checked locking pattern herumhantieren, aber sie sind nicht nur komplizierter, sondern schlicht unbrauchbar: The "Double-Checked Locking is Broken" Declaration
 
Wenn man wirklich ein lazy-loading, thread-safe Singleton haben will, gibt es - so weit ich weiß - nur zwei einfache und wirklich "saubere" Lösungen:
Was dabei oft missverstanden wird, die einfache Variante das Feld direkt zu initialisieren ist auch fast immer Lazy Loading, weil die Variable erst dann initialisiert wird wenn die Klasse geladen wird, also wenn sie wirklich gebraucht wird.
Der einzige Fall in dem die Instanz zu früh erstellt werden würde, ist wenn die Klasse, oder statische Methoden der Klasse verwendet werden ohne das auch gleich nach der Singleton Instanz gefragt wird. Und dafür gibt es nun wirklich fast keinen validen Use-Case.
 
Gibt es irgendwo ein Beispiel, wie man mit Dependency Injections Singeltons ersetzen kann?
Wirklich jedes DI Framework beschreibt genau das in der Doku.

Ist gar nicht so komplex wie man meint, Singletons stellen externe Abhängkeiten dar, diese werden in DI entweder per Setter, Konstruktor oder Annotationen "injeziert", also als Parameter übergeben.
 
Die Frage hatte gar nix mit Singletons zu tun. Der Threadsteller fragt einfach nur warum er den Typ vor eine Variable schreiben muss. Ja weil eine Variable halt einen Typ braucht! Man muss ja issen ob instanz eine Zahl, ein Kunde, ein Huhn oder dein Singelton Objekt ist.

Gibt es irgendwo ein Beispiel, wie man mit Dependency Injections Singeltons ersetzen kann?
Wie jetzt konkret ein Code Beispiel?

Statt
Java:
public class SingletonUser {

   public void doSomethingWithSingleton(){
      Singleton.getInstanz().doSometing(); 
   }
}

sich zb per Konstruktor Injection das Teil setzen lassen

Java:
public class SingletonUser {
   
   private Singleton singleton;
   
   
   public SingletonUser(Singleton singleton) {
      super();
      this.singleton = singleton;
   }


   public void doSomethingWithSingleton(){
      singleton.doSometing(); 
   }
}
Wobei jetzt Singleton eine ganz normale POJO wäre und keine static instanz und private Konstrutor braucht. Und ein Bissal Konfig je nach DI Framework noch fehlt
 
In Guice kann man entweder die zu injizierende Klasse mit [c]@Singleton[/c] annotieren, oder alternativ als Eigenschaft beim Binden angeben. Für die Klasse, die das Ding injiziert bekommt, sieht das Singleton wie jeder andere injizierte Wert aus.
 
Hallo,
das hier diskutierte Pattern ist veraltet. Die verschiedenen Nachteile sind ja bereits ausführlich diskutiert worden. Seit Java 5 gibt es ein viel robusteres Pattern mit Enums.

Java:
public enum MySingleton {
  INSTANCE;
  ... felder ...
  ... methoden ...
}
Das ist schon alles. Die Vorteile sind: Viel weniger Code, es gibt keine Probleme mit Threads, es ist unter keinen Umständen möglich, dass man aus versehen doch mehrere Instanzen erzeugt, enums sind sogar out of the box serializable.

Zugriff erfolgt über MySingleton.INSTANCE.

Gruß nillehammer
 
Man sieht oft wilde Implementierungen, die mit synchronized und dem double-checked locking pattern herumhantieren, aber sie sind nicht nur komplizierter, sondern schlicht unbrauchbar: The "Double-Checked Locking is Broken" Declaration

wenn es nicht gerade um eine komplette Klasse geht sondern um einfache Instanzattribute dann sind die meisten bis alle hier genannten Varianten ja wenig hilfreich,
zum DoubleCheckedLocking mag wer will vielleicht jemand in meinen Thread schauen:
http://www.java-forum.org/allgemeine-java-themen/122208-double-checked-locking.html
 
Wirklich jedes DI Framework beschreibt genau das in der Doku.

Ich habe etwas recherchiert und festgestellt, dass JEE6 in der Regel benötigt wird. Was ist nun, wenn ich einfach nur ne Desktop Applikation z.B. in Swing entwickle. Nehme ich da auch ein DI Framework als Ersatz für:
Java:
public static Singelton getInstanz(){
      if (instanz == null)
         instanz = new Singelton();
      return instanz;
   }

Der Tipp von nillehammer mit ENUM gefällt mir ganz gut.
 
Ich habe etwas recherchiert und festgestellt, dass JEE6 in der Regel benötigt wird.
Weder Spring noch Guice brauchen JEE 6, hast wohl nicht so gut recherchiert 😉
JEE6 bietet (C)DI, hast du wohl verwechselt.


Was ist nun, wenn ich einfach nur ne Desktop Applikation z.B. in Swing entwickle. Nehme ich da auch ein DI Framework als Ersatz für:
Natürlich.

Java:
public static Singelton getInstanz(){
      if (instanz == null)
         instanz = new Singelton();
      return instanz;
   }
Frage an dich freeze:
Wozu das Lazy Init?

Bei kleinen Systemen (ohne JEE oder Spring) würde ich auch Guice empfehlen.
Kann Guice auch für große Systeme empfehlen 🙂
 
Kann Guice auch für große Systeme empfehlen 🙂

Ich auch, aber in dem Bereich in dem ich arbeite (Web-Backends ^^), sind große Systeme meistens schon auf JEE oder Spring Basis. Dort wird meistens kaum einer auf Guice aufbauen.
Das es auch für größere Dinge wunderbar ist sehe ich an meinem Chatserver, der um Guice herum ein großes Framework aufgebaut hat 🙂
 

Zurück
Oben