# Singleton mit Parametern im Konstruktor



## Mappenz (14. Jun 2011)

Hi

ich habe unter anderem folgende Klassen gegeben:

```
import java.util.ArrayList;

/* Der Geschäftsführer ist der (einzige) oberste Chef der Firma. */
public class Geschaeftsfuehrer extends Person {
    ArrayList<Abteilungsleiter> abteilungsleiter = new ArrayList<Abteilungsleiter>();

    public Geschaeftsfuehrer(String vname, String nname) {
        super(vname, nname);
    }

    public void fuegeAbtLeiterHinzu(Abteilungsleiter al) {
        abteilungsleiter.add(al);
    }
}
```

und 

[Java]


public class Person {
    // bei uns verdienen erst einmal alle gleich viel ...
    public int gehalt = 42;
    public String vorname;
    public String nachname;

    public Person(String vname, String nname) {
        vorname = vname;
        nachname = nname;
    }


    public String gibName() {
        return vorname + " " + nachname;
    }
}
[/code]

Nun ist es meine Aufgabe den Code zu verschönern. Ich bin schon darauf gekommen, dass der Geschäftsführer ein Singleton sein sollte. Das war ja mit dem Kommentar auch nicht so schwer. Das Muster habe ich auch im GOF Entwurfsmuster nachgeschlagen. In seiner Reinform ist dieses Muster das einfachste von allen. Da ich aber für den Konstruktoraufruf Parameter brauche ist folgender Code nicht möglich:

[Java] 
public getGeschaeftsfuehrer() {
    if ( geschaeftsfuehrer == null) { // private static geschaeftsfuehrer existiert nun entsprechend dem Vorbild aus GOF
       geschaeftsfuehrer = new Geschaeftsfuehrer(); 
    } return geschaeftsfuehrer;
}
[/code]

Ich möchte nicht, dass der Klient immer 
	
	
	
	





```
getGeschaeftsfuehrer()
```
 parametrisiert aufrufen muss. Ich möchte auch nicht, dass 
	
	
	
	





```
getGeschaeftsfuehrer()
```
 Geschaeftsfuehrer ohne Namen zurück gibt (Vielleicht muss ich diesen Wunsch aufgeben), also ist es auch nicht gut einen Standardkonstruktor zu erstellen. 

Dieses Problem ist nicht ganz neu, meine eigenen Recherchen haben einige Lösungsvorschläge in C++ und C# gefunden. Von den Schwierigkeiten die ich mit diesen Sprachen hatte abgesehen waren alle Lösungen viel zu Kompliziert und nach meinem Geschmack zu weit vom Ideal aus dem Buch entfernt.

Wie wird ein Singleton, das Parameter im Konstruktor benötigt einfach und sauber konstruiert?

gruß
Michi


----------



## maki (14. Jun 2011)

> Wie wird ein Singleton, das Parameter im Konstruktor benötigt einfach und sauber konstruiert?


Ist doch egal ob mit oder ohne Parameter, die Objekterzeugung sollte unabhängig davon sein, wie es verwendnet wird.

Finde deine Idee mit dem Singleton Geschäftsführer schlecht, das GoF Singleton Pattern an sich hat genug Probleme und Einschränkungen, einfach mal suchen, "schöner" wird der Code dadurch nicht.

Das Composite Pattern würde das viel besser passen, da es sich um eine Hierarchische Struktur handelt.


----------



## SlaterB (14. Jun 2011)

maki hat gesagt.:


> die Objekterzeugung sollte unabhängig davon sein, wie es verwendnet wird.


unabhängig von guter und böser Bewertung,
widerspricht das nicht einem der Grundprinzipien der ganzen Sache?


> Von Lazy Creation spricht man, wenn das einzige Objekt der Klasse erst erzeugt wird, wenn es benötigt wird.
> [..]
> if (instance == null) {    instance = new Singleton();       }
> return instance;


Singleton (Entwurfsmuster) ? Wikipedia


----------



## maki (14. Jun 2011)

SlaterB hat gesagt.:


> unabhängig von guter und böser Bewertung,
> widerspricht das nicht einem der Grundprinzipien der ganzen Sache?
> 
> Singleton (Entwurfsmuster) ? Wikipedia


Erzeugung und Verwendung (Zugriff)  sind beim GoF Singleton leider verwoben.

Ein Singleton muss zB. kein Lazy Init bieten, ist in den meisten Fällen sogar ein Nachteil, aber weil Wiki bzw. fast alle Quellen nur Lazy Init Singletons zeigen, machen dass die meisten so 

Bloch zeigt in seinem "Effective Java 2nd Edition" alternativen, zB. den Singleton holder oder Enums als Singleton zu verwenden.

Ob der private Konstruktor Parameter entgegennimmt oder nicht, ist nicht wichtig fürs GoF Singleton Pattern an sich.
Jedenfalls müssen die Parameter bei Erzeugung bekannt sein, und dass muss auch unabhängig vom Singleton "Client" sein.


----------



## Mappenz (14. Jun 2011)

Danke für die Antworten,

in der Zwischenzeit habe ich mir die Aufgabe nocheinmal angeschaut. So sieht das Ergebnis aus.

```
import java.util.ArrayList;

/* Der Geschäftsführer ist der (einzige) oberste Chef der Firma. */
public class Geschaeftsfuehrer extends Person {
	//entspricht static einzigesExemplar
	private static Geschaeftsfuehrer gf = null;
	//entspricht SingletonDaten
    ArrayList<Abteilungsleiter> abteilungsleiter = new ArrayList<Abteilungsleiter>();

    private Geschaeftsfuehrer(String vname, String nname) {
        super(vname, nname);
    }
    
    public static Geschaeftsfuehrer newGeschaeftsfuehrer(String vname, String nname) {
    	gf = new Geschaeftsfuehrer(vname, nname);
    	return gf;
    }
    //entspricht static Exemplar()
    public static Geschaeftsfuehrer getGeschaeftsfuehrer() {
    	return gf;
    }
    //entspricht SingletonOperation()
    public void fuegeAbtLeiterHinzu(Abteilungsleiter al) {
        abteilungsleiter.add(al);
    }
    //GibSingletonDaten() braucht keine Entsprechung
}
```
Recht trivial die Änderungen, da hätte ich früher drauf kommen können, es ist auch noch recht nahe am Muster und erfüllt seine Funktion. Was meint ihr dazu?

Die Komposition schaue ich mir jetzt gleich mal an. Verhindert die Komposition dass es mehr als einen Geschäftsführer gibt?


----------



## maki (14. Jun 2011)

> Die Komposition schaue ich mir jetzt gleich mal an. Verhindert die Komposition dass es mehr als einen Geschäftsführer gibt?


Ich meinte das Composite Pattern, übersetzt: "Kompositium", nicht "Komposition", das ist etwas anderes.

Auch ein Singleton verhindert nicht dass es mehr als einen Geschäftsführer gibt, es reicht doch, ihn nur einmal zu erzeugen.

Du hast jetzt eine FactoryMethode direkt in der Geschäftsführer Klasse, dass ist nicht dasselbe wie ein Singleton sondern ein anderes Muster, aber schon besser imho


----------



## SlaterB (14. Jun 2011)

ich spiel erneut die Stimme, die du überlegen ignorierst, obwohl du es immer gleich dazu schreiben könntest:
wieso ist das kein Singleton?
von Wikipedia sind alle Eigenschaften erfüllt


> Eigenschaften
> 
> Das Einzelstück (Singleton)
> 
> ...


----------



## maki (14. Jun 2011)

SlaterB hat gesagt.:


> ich spiel erneut die Stimme, die du überlegen ignorierst, obwohl du es immer gleich dazu schreiben könntest:
> wieso ist das kein Singleton?
> von Wikipedia sind alle Eigenschaften erfüllt


Vielleicht verstehe ich dich auch nur falsch SlaterB.

Der letzte Code vom TS ist kein GoF Singleton, weil nirgendwo sichergestellt wird, dass die Methode newGeschaeftsfuehrer nur einmal aufgerufen wird, genaugenommen wird die Methode in dem vorgestelltem Code gar nicht aufgerufen.

Wenn man sich nun das FacoryMethod Pattern anguckt, merkt man, dass es das ist was der TS "erfunden" hat (bitte nicht mit der AbstractFactory verwecheseln, ist ähnlich, aber viel komplexer/flexibler).


----------



## Mappenz (14. Jun 2011)

Stimmt, Kompositum hatte ich aber auch im Kopf.

Aber wie verhindert ein Singleton nicht, dass es mehr als einen Geschaeftsfuehrer gibt, das ist doch der Zweck dieses Musters. Die Klasse verwaltet ja schließlich auch das Exemplar. Der Konstruktor ist private.

Es reicht ganz sicher nicht einfach nur einen Geschaeftsfuerer zu erzeugen. Du könntest Argumentieren, dass man in diesem kleinen Bsp. den Überblick behält was man erzeugt. Es geht hier aber darum zu üben wie man eine saubere Architektur baut und dazu gehört auch dass der Kunde nichts kann was er nicht tun soll. In einem großen Programm könnte ich zum Beispiel vergessen dass ich schon einen Geschaeftsfuehrer habe und einen Zweiten erzeugen. Mir fällt auf, dass mein Programm so wie es jetzt ist dieses Problem nicht lösen würde. Das Singleton aus dem Buch schon.
Egal, der Punkt war es reicht nicht, einfach nur einen Geschaeftsfuehrer zu erzeugen.

Fabrikmethode, hmm, nochmal nachschlagen...

gruß
Michi


----------



## SlaterB (14. Jun 2011)

@maki
ok, da lag ich falsch, das hätte ich auch sehen können,
war noch von der vorherigen Antwort eingeseift und erwartete jetzt wieder 'in Buch xy steht nämlich ..' ..


----------



## Mappenz (14. Jun 2011)

die Funktion wird im Klienten aufgerufen, wie oft ist egal, in diesem Bsp allerdings nur einmal, der Klient:


```
public class Firma {
    public String firmenname;
    public Geschaeftsfuehrer gf;

    /**
     * @param args Kommandozeilenargumente
     */
    public static void main(String[] args) {
        // Erstelle die Firma
        Geschaeftsfuehrer gf = Geschaeftsfuehrer.newGeschaeftsfuehrer("Walter", "Tichy");
        Firma f = new Firma("Entwurfsmuster GmbH", gf);

        // Statte den Geschäftsführer mit Abteilungsleitern aus
        Abteilungsleiter al1 = new Abteilungsleiter("Victor", "Pankratius");
        gf.fuegeAbtLeiterHinzu(al1);
        Abteilungsleiter al2 = new Abteilungsleiter("Ali", "Jannesari");
        gf.fuegeAbtLeiterHinzu(al2);

        // Gib den Abteilungsleitern ein paar Teamleiter
        // Pankratius
        Teamleiter tl1 = new Teamleiter("Frank", "Otto");
        al1.fuegeTeamleiterHinzu(tl1);
        Teamleiter tl2 = new Teamleiter("Jochen", "Schimmel");
        al1.fuegeTeamleiterHinzu(tl2);

        // Jannesari
        Teamleiter tl3 = new Teamleiter("Andreas", "Höfer");
        al2.fuegeTeamleiterHinzu(tl3);
        Teamleiter tl4 = new Teamleiter("Sven", "Körner");
        al2.fuegeTeamleiterHinzu(tl4);

        // und manchen Teamleitern ein paar Mitarbeiter
        Mitarbeiter m1 = new Mitarbeiter("Max", "Udri");
        tl1.fuegeMitarbeiterHinzu(m1);

        Mitarbeiter m2 = new Mitarbeiter("Ihssane", "El-Oudghiri");
        tl2.fuegeMitarbeiterHinzu(m2);

        // und nun gib mir die Hierarchie aus
        f.gibHierarchieAus();
    }

    public Firma(String firmenname, Geschaeftsfuehrer gf) {
        this.firmenname = firmenname;
        this.gf = gf;
    }

    public void gibHierarchieAus() {
        System.out.println("|-- Geschäftsführer: " + gf.gibName());
        for (Abteilungsleiter al : gf.abteilungsleiter) {
            System.out.println("  |-- Abteilungsleiter: " + al.gibName());
            for (Teamleiter tl : al.teamleiter) {
                System.out.println("    |-- Teamleiter: " + tl.gibName());
                for (Mitarbeiter m : tl.mitarbeiter) {
                    System.out.println("      |-- Mitarbeiter: " + m.gibName());
                }
            }
        }
    }

}
```


----------



## schalentier (14. Jun 2011)

Mappenz, jetzt hast du kein Singleton mehr, da du beliebig viele Geschaeftsfuehrer anlegen kannst. Mach das wieder weg und vergiss das Singleton am besten einfach ;-)

Viel sinnvoller waere in diesem Beispiel ein korrektes Composite-Pattern zu implementieren.


----------



## Mappenz (14. Jun 2011)

Es ist richtig, dass das GoF Singleton nur ein einziges mal den Konstruktor aufruft. Aber ist das denn der Knackpunkt? Da der Konstruktor Parameter enthält muss ich ohnehin von davon abweichen. Ist es nicht viel bedeutender, dass es nur eine Instanz gibt? Ich muss auch deshalb davon abweichen, weil es möglich sein sollte den Geschäeftsfuehrer auszuwechseln.

Du sagst es spielt für das GoF Singleton keine Rolle ob der Konstruktor Parameter enthält oder nicht, ich bin nicht in der Lage zu sehen wie das keine Rolle spielen kann. Wie sollte denn Exemplar() aussehen mit Parametern?


----------



## maki (14. Jun 2011)

> Die Funktion wird im Klienten aufgerufen, wie oft ist egal, in diesem Bsp allerdings nur einmal, der Klient:


Tja, dann musst du sicherstellen dass der Client es richtig macht und die Methode 
nur einal aufruft 


> Aber wie verhindert ein Singleton nicht, dass es mehr als einen Geschaeftsfuehrer gibt, das ist doch der Zweck dieses Musters. Die Klasse verwaltet ja schließlich auch das Exemplar. Der Konstruktor ist private.


Es gibt meherere Wege wie Singletons zu "Fewtons" mutieren, Serialisierung, ein andere ClassLoader/VMs und so weiter, Singleton hilft in großem Rahmen nicht mehr, höchstens im kleinen.



> Es reicht ganz sicher nicht einfach nur einen Geschaeftsfuerer zu erzeugen. Du könntest Argumentieren, dass man in diesem kleinen Bsp. den Überblick behält was man erzeugt. Es geht hier aber darum zu üben wie man eine saubere Architektur baut und dazu gehört auch dass der Kunde nichts kann was er nicht tun soll. In einem großen Programm könnte ich zum Beispiel vergessen dass ich schon einen Geschaeftsfuehrer habe und einen Zweiten erzeugen. Mir fällt auf, dass mein Programm so wie es jetzt ist dieses Problem nicht lösen würde. Das Singleton aus dem Buch schon.
> Egal, der Punkt war es reicht nicht, einfach nur einen Geschaeftsfuehrer zu erzeugen.


in einer saubereren Architektur vermeidet man unnötige Abängigkeiten, das geht mit dem GoF Singleton nicht, da man eine static Methode/Variable referenziert.
In großen Projekten nimmt man seit Jahren nicht mehr ein halbes Dutzend Singletons, hat eben Nachteile.
Stattdessen macht man in sauberen Projekten implizite Abhängigkeiten explizit und nutzt DI (Depdency injection) mit Framework, das konfiguriert man dann richtig, und schon ist sichergestellt, wie oft ein Object erzeugt wird, Spring, Guice, EJB etc. bieten dafür zB. eine Annotation: @Singleton

Die meisten "Muster Anfänger" meinen, sie müssten nur das GoF Buch nehmen und das so viele Pattern wie möglich einbauen um ein gutes Design zu bekommen, Singleton wird oft deswegen so häufig genutzt, weil es so einfach ist 
Das man dadurch kein gutes Design bekommt ist selbstredend.

@SlaterB
Tut mir leid falls ich arrogant geklungen hab, war keine Absicht.


----------



## Mappenz (14. Jun 2011)

Ok, das Singleton vergesse ich gleich wieder. Aber zuerst: Wie soll ich beliebig viele Geschaeftsfuehrer anlegen können? Zu jedem Zeitpunkt kann es nur einen Geschaeftsfuehrer geben.


----------



## schalentier (14. Jun 2011)

```
Geschaeftsfuehrer gf  = Geschaeftsfuehrer.newGeschaeftsfuehrer("Walter", "Tichy");
        Geschaeftsfuehrer gf2 = Geschaeftsfuehrer.newGeschaeftsfuehrer("Walter", "Tichy");
        Geschaeftsfuehrer gf3 = Geschaeftsfuehrer.newGeschaeftsfuehrer("Walter", "Tichy");
```


----------



## Mappenz (14. Jun 2011)

hehe, das war einfach. Obwohl, zeigen gf gf2 und gf3 nicht auf das selbe statische Objekt?


----------



## schalentier (14. Jun 2011)

```
public static Geschaeftsfuehrer newGeschaeftsfuehrer(String vname, String nname) {
        gf = new Geschaeftsfuehrer(vname, nname);
        return gf;
}
```

Nein ;-)


----------



## Mappenz (14. Jun 2011)

Ja, das muss ich wohl einsehen. Ich hatte nicht verstanden, dass man Referenzen auf das Objekt, statt auf die Referenz gf, zurück bekommt. Gibt es in Java Referenzen auf Referenzen?

Das Singleton hat mich nicht losgelassen, so sollte mein Code doch als Singleton durchgehen, richtig?


```
import java.util.ArrayList;

/* Der Geschäftsführer ist der (einzige) oberste Chef der Firma. */
public class Geschaeftsfuehrer extends Person {
	//entspricht static einzigesExemplar
	private static Geschaeftsfuehrer gf = null;
	//entspricht SingletonDaten
    ArrayList<Abteilungsleiter> abteilungsleiter = new ArrayList<Abteilungsleiter>();

    private Geschaeftsfuehrer(String vname, String nname) {
        super(vname, nname);
    }
    
    public static Geschaeftsfuehrer wechselGeschaeftsfuehrer(String vname, String nname) {
    	if(gf == null) {
    		gf = new Geschaeftsfuehrer(vname, nname);    		
    	} else {
    		gf.vorname = vname;
    		gf.nachname = nname;
    	}
    	return gf;
    }
    //entspricht static Exemplar()
    public static Geschaeftsfuehrer getGeschaeftsfuehrer() {
    	return gf;
    }
    //entspricht SingletonOperation()
    public void fuegeAbtLeiterHinzu(Abteilungsleiter al) {
        abteilungsleiter.add(al);
    }
    //GibSingletonDaten() braucht keine Entsprechung
}
```

Ich setze das Projekt mal zurück und schaue wie ich mit Kompositum weiter komme. Damit ist der Thread glaube ich auch an seinem Ende angelangt. Danke allen die sich Beteiligt haben :toll:.


----------

