# Singleton Pattern passend hierfür?



## SilentBob (14. Mai 2008)

Hallo,

Ich habe einen JFrame mit bisher 6 TabbedPanes drin, könnten auch bis zu 10 werden.

Nun haben diese 6 GUI Klassen zur Unterscheidung namen wie xxxView während die dazugehörigen Klassen mit den Methoden xxxControl heißen und evtl. gibts noch xxxModel Klassen die Daten aufnehmen.

Nun sind das ganze ca. 15 Klassen. Jede der Klasse greift mehr/weniger auf andere Klassen zu. Nun habe ich natürlich das WirrWarr, dass ich die erzeugten Objekte der GUI KLassen oder die Objekte der Control Klassen überall hindurchreichen muss, denn ein 2. Objekt der GUI Klasse geht nicht, da ich sonst einen NullPointer  bekomme. Das ganze sieht dann natürlich nicht so elegant aus und viele KLasse haben 3 Parameter im Konstruktor.

Nun frage ich mich ob es nicht ideal wäre das Singleton Pattern hier anzuwenden:

1. damit objekte auch sicher nur einmal erzeugt werden und ich nicht immer darauf achten muss ja das Objekt richtig weiterzugeben etc

2. damit ich eine angebliche so las ich es GLOBALE Stelle habe wo ich das Objekt abholen kann. Wäre super geschickt, wenn ich nicht immer von hir nach da und dort das Objekt reiche...

3. und das Single-Objekt wird nur erstellt wenns benötigt wird, spart Ressourcen.

Ist das Singleton ok für diesen Anwendungsfall? was denkt Ihr? Hat mir vielleicht jemand gute Links mit Anwendungsfällen dieser Komplexität?


----------



## diggaa1984 (14. Mai 2008)

also ich würde es vermutlich damit realisieren. Eine zentrale Klasse welche vielleicht alle Tabs kennt und dies auf Anfragen einzeln oder auch alle auf einmal, je nach bedarf zurückgeben kann.

ich habe dieses Pattern verwendet um eine zentrale Anlaufstelle für meine Datenmanipulation zu bekommen, welche von Tabellen, Menüs, Buttons oder Interaktion mit Zeichnungen vollzogen werden. Wenn ich was zu manipulieren habe, dann hole ich mir die Instanz der Singleton-Klasse, und kann dann mit Hilfe derer Methoden die Daten manipulieren, welche nur indirekt über dieses Singleton bearbeitet werden können. Beim Auslesen von Daten werden nur Kopien nach Aussen weitergereicht.


----------



## Gast (14. Mai 2008)

Ich weiß ja nicht genau was deine "views" darstellen. Vielleicht muss das ja bei dir so sein. 

Aber pauschal kann man sagen, wenn dir die Abhängigkeiten zu komplex erscheinen, solltest du nochmal die Codestruktur überarbeiten. Das Signleton Pattern ist sicherlich in vielen Fällen sehr sinnvoll, aber wird doch meist als Alheilmittel gegen eine schlechte Codestruktur ein gesetzt. 

Ohne deine Code zu kennen wage ich zu behaupten bei die könnte es ähnlich sein. Du könntest dir mal etwas generelles zur GUI Entwicklung durchlesen, dann weist du sicherlich ob ich recht habe oder nicht. Ein Grundlegendes Stichwort in diesem ZUsammenhang ist MVC


----------



## SilentBob (14. Mai 2008)

diggaa1984 hat gesagt.:
			
		

> also ich würde es vermutlich damit realisieren. Eine zentrale Klasse welche vielleicht alle Tabs kennt und dies auf Anfragen einzeln oder auch alle auf einmal, je nach bedarf zurückgeben kann.
> 
> ich habe dieses Pattern verwendet um eine zentrale Anlaufstelle für meine Datenmanipulation zu bekommen, welche von Tabellen, Menüs, Buttons oder Interaktion mit Zeichnungen vollzogen werden. Wenn ich was zu manipulieren habe, dann hole ich mir die Instanz der Singleton-Klasse, und kann dann mit Hilfe derer Methoden die Daten manipulieren, welche nur indirekt über dieses Singleton bearbeitet werden können. Beim Auslesen von Daten werden nur Kopien nach Aussen weitergereicht.



1.) Warum wird denn nicht das MVC zusamme mit Singleton Pattern verwendet?

2.) Das MVC macht bei mir wenig Sinn, denn ich habe von den 6 tabs nur 1 model Klasse und zwar diejenige, die die konfigurations xml-daten aufnimmt.

Meine Anwendung ist ja eh schon strukturiert sprich GUI Klassen enthalten nur Elemente wie buttons/labels etc und "Controller"-Klassen die die Methoden enthalten um daten zu berechnen... um diese in der View Klasse auszugeben etc...

3.) was diggaa1984 vorschlägt hört sich gut an.


----------



## Marco13 (14. Mai 2008)

Gast hat gesagt.:
			
		

> Das Signleton Pattern [...] wird doch meist als Alheilmittel gegen eine schlechte Codestruktur ein gesetzt.


Da stimme ich mal zu, und prognostiziere, dass es hier auch so werden wird. Man macht sich das Leben leicht, "weil das so praktisch ist, und man von überall drauf zugreifen kann"... aber Struktur hat das i.a. keine. Und wer sich schon mit Programmen rumschlagen mußte, wo lauter Singletons über alle Grenzen hinweg miteinander kommunizieren, und dort dann ein Singleton eben nichtmehr "single" sein durfte, weiß, was das bedeuten kann...

EDIT: Halt, nein  :shock: ich stimme nicht zu, sondern widerspeche: Es ist definitiv KEIN Heilmittel. (Eher ein "süßes Gift"  :wink: )


----------



## diggaa1984 (14. Mai 2008)

Versteh zwar eure sorgen bezüglich dieses patterns, aber wie könnte man es denn anders organisieren, ohne mittels Setter oder Parameter im Konstruktor Objekte hin und her zu reichen (was mir in grossen Programmen vom code her mal gar nich zusagt) ... klar is das singleton von jedem erreichbar der es gern hätte, aber ich finde solange man keine nebenläufigen threads hat die damit spielen ist das doch eine gute wahl  :bahnhof: ???:L

Ich für meinen Teil hab bisher 3 Klassen welche den Zugriff brauchen - es werden vermutlich noch 2-3 hinzu kommen. und dort linear was durchzureichen (ausgehend von einer instanz in klasse X) is für mich nicht wirklich akzeptabel


----------



## SilentBob (14. Mai 2008)

Marco13 hat gesagt.:
			
		

> Gast hat gesagt.:
> 
> 
> 
> ...


----------



## diggaa1984 (14. Mai 2008)

ich glaub da ein Aspekt der wartbarkeit zu erkennen ;D


----------



## Marco13 (14. Mai 2008)

Es gibt zwei Preise. Preis A und Preis B. Wenn man eine wahre Aussage macht, bekommt man Preis A. Wenn man eine falsche Aussage macht, bekommt man Preis A _nicht_. Was muss man sagen, um Preis B zu bekommen?

(DAS ist ein Rätsel   )

Es ging natürlich um die Wartbarkeit und Erweiterbarkeit. Wenn man sowas hat wie ein DatenSingleton, und überall, wo etwas gemacht wird, wird mit dem DatenSingleton rumhantiert. In den Einlese-Methoden werden Daten aus Dateien gelesen und dort reingeschrieben. Irgendwoanders wird mit diesen Daten rumgerechnet. Im GUI werden diese Daten angezeigt. Und irgendwann merkt man, dass man die Daten ZWEI mal braucht, um z.B. unterschiedliche Berechnungen drauf anzuwenden. Dann muss man seine komplette "Architektur" über den Haufen werfen. Oder man macht dann einfach ein Multiton.


```
class DataMultiton
{
    private static DataMultiton instance = new DataMultiton();
    public static DataMultiton getInstance() { return instance; }

    private static DataMultiton otherInstance = new DataMultiton();
    public static DataMultiton getOtherInstance() { return otherInstance; }
}
```
(jetzt spreche ich nicht in Rätseln, sondern in Witzen :roll: )


----------



## diggaa1984 (15. Mai 2008)

ja an sich verständlich, aber nu die Frage .. soll etwa x mal die eine instanz die IRGENDWO erstellt wurde durchreichen? glaube nich das das in grossen programmen möglich ist, bzw würde ich auch keine Instanz einer DatenKlasse derart rumreichen. auch bei MVC muss ich irgendwie an die daten kommen oder nicht?


----------



## SilentBob (15. Mai 2008)

diggaa1984 hat gesagt.:
			
		

> dann hole ich mir die Instanz der Singleton-Klasse, und kann dann mit Hilfe derer Methoden die Daten manipulieren, welche nur indirekt über dieses Singleton bearbeitet werden können. Beim Auslesen von Daten werden nur Kopien nach Aussen weitergereicht.


 angeblich werden die instanzen ja vom Singleton erzeugt, doch wie soll das bei mir gehen fällt mir grade auf, wenn meine Instanzen sprich jtabbedPanes beim anzeigen erzeugt werden??? ich kann ja nicht den jframe laden und die jtabbedpanes darin nicht...


----------



## tfa (15. Mai 2008)

diggaa1984 hat gesagt.:
			
		

> ja an sich verständlich, aber nu die Frage .. soll etwa x mal die eine instanz die IRGENDWO erstellt wurde durchreichen? glaube nich das das in grossen programmen möglich ist, bzw würde ich auch keine Instanz einer DatenKlasse derart rumreichen.


Warum sollte das nicht möglich sein? Wenn es Abhängigkeiten zwischen Objekten gibt, müssen sie sich natürlich irgendwie kennen. Dabei ist es völlig egal, ob man die Verbindung mit Gettern und Setter, Konsturktorparametern oder Dependency Injection herstellt - Hauptsache man missbraucht keine Singletons hierfür.


----------



## diggaa1984 (15. Mai 2008)

SilentBob hat gesagt.:
			
		

> angeblich werden die instanzen ja vom Singleton erzeugt, doch wie soll das bei mir gehen fällt mir grade auf, wenn meine Instanzen sprich jtabbedPanes beim anzeigen erzeugt werden??? ich kann ja nicht den jframe laden und die jtabbedpanes darin nicht...


ne das Singelton wäre hier eine Klasse welche die Verweise auf die JTabbedPanes speichert, sprich diese müssten sich beim Erzeugen in der Klasse melden und sagen "hier bin ich". Andere Klassen würden dann über die Singleton-Klasse die Verweise anfordern.




			
				tfa hat gesagt.:
			
		

> Warum sollte das nicht möglich sein? Wenn es Abhängigkeiten zwischen Objekten gibt, müssen sie sich natürlich irgendwie kennen. Dabei ist es völlig egal, ob man die Verbindung mit Gettern und Setter, Konsturktorparametern oder Dependency Injection herstellt - Hauptsache man missbraucht keine Singletons hierfür.


was mir daran missfällt ist bei mir zB die Tatsache, dass ich das Objekt durch Klassen reichen muss die es nicht benötigen, zB: habe eine Klasse MainFrame, welche das Hauptfenster darstellt, dann eine Klasse MyJMenuBar, welche das Menü aufbaut und Funktionen des Singleton aufruft. da nur der MainFrame diese Menü-Klasse kennt müsste ich da schon anfangen mit Durchreichen, denn Panels welche auf dem MainFrame landen brauchen auch den Singleton-verweis (CardPanels). Und da hätte ich in der MainFrame schon den. meines Erachtens, unnützen Verweis auf diese noch-Singleton-Klasse.
Und ich kann mir gut vorstellen das es in größeren Programmen öfter derartige Vorfälle gibt.


----------



## ms (15. Mai 2008)

Wenn man jede Klasse als eigenständig betrachtet und sich nur auf den Fokus dieser Klasse konzentriert dann wird man genau wissen ob jede Klasse eine Referenz auf dein Datenobjekt benötigt oder nicht.

Mit dem Singleton-Pattern wird festgelegt dass es nur eine Instanz einer Klasse gibt.
Kommt also nur zum Tragen beim Erstellen des Objekts.
Das hat absolut nichts mit dem herumreichen durch verschiedene andere Klassen zu tun.
Es kann den anderen Klassen egal sein, wie das Objekt erstellt wurde und wie viele Instanzen es von dieser Klasse gibt, denn sie benutzen es nur. 
Ok, irgendwo wird das Objekt erstellt, aber das passiert ja nicht in allen Klassen.
Die anderen Klassen sollten sich auf ihren Fokus konzentrieren, also was sie mit dem Objekt machen und wie sie es benutzen.
Dein Beispiel ist ein klassischer Fall von high coupling => direkte Abhängigkeit auf die Factory und möglicherweise werden die anderen Klassen mit Rücksicht auf nur eine existierende Klasse programmiert.
Genau so sollte es nicht gemacht werden.

ms


----------



## diggaa1984 (15. Mai 2008)

ms hat gesagt.:
			
		

> Wenn man jede Klasse als eigenständig betrachtet und sich nur auf den Fokus dieser Klasse konzentriert dann wird man genau wissen ob jede Klasse eine Referenz auf dein Datenobjekt benötigt oder nicht.
> 
> Dein Beispiel ist ein klassischer Fall von high coupling => direkte Abhängigkeit auf die Factory und möglicherweise werden die anderen Klassen mit Rücksicht auf nur eine existierende Klasse programmiert.
> Genau so sollte es nicht gemacht werden.



Eben diesen Fokus der Klassen habe ich ja berücksichtigt, und da mein MainFrame keine Interaktion mit dem Singleton haben wird, blieb mir eigentlich nur der Singleton, da ich dieses Rumreichen ja nicht gern sehe.

Deiner Meinung nach müsste ich also zB die Singleton-Klasse im MainFrame oder evt. noch weiter vorher instanziieren und einfach ans Menü und die Panels reichen, die wiederum das Objekte an weitere Klassen reichen (sofern ich diese benötige um mein Programm besser zu strukturieren)? Und aus dem Singleton quasi ne normale Klasse machen.

was genau meinst du mit high-coupling? Die Anzahl der Zugriffe oder Verweise auf diese Klasse wird ja nich weniger.
Oder meinst du damit, dass die Klassen, welche das Singleton nutzen, zu sehr auf dieses zugeschnitten sind?


----------



## ms (15. Mai 2008)

diggaa1984 hat gesagt.:
			
		

> Die Anzahl der Zugriffe oder Verweise auf diese Klasse wird ja nich weniger.


Richtig, darum bringt dir auch das Singleton nichts, die Verweise sind sowieso da.



			
				diggaa1984 hat gesagt.:
			
		

> Oder meinst du damit, dass die Klassen, welche das Singleton nutzen, zu sehr auf dieses zugeschnitten sind?


Ja das meine ich. 

Das Singleton-Pattern ist nicht dazu da, dem Programmierer Verweise zu ersparen.

Nochmal, betrachte einfach jede Klasse für sich. Was tut diese Klasse, was für einen Zweck erfüllt sie und was benötigt sie um diesen Zweck zu erfüllen. Wenn sie eine Referenz auf deine Datenklasse benötigt dann wirst du nicht drum herumkommen eine Referenz davon zu halten. 
Ein "Durchreichen" kann übrigens auch Zweck sein (Delegate).

ms


----------



## maki (15. Mai 2008)

> was genau meinst du mit high-coupling? Die Anzahl der Zugriffe oder Verweise auf diese Klasse wird ja nich weniger.
> Oder meinst du damit, dass die Klassen, welche das Singleton nutzen, zu sehr auf dieses zugeschnitten sind?


"high-coupling" beudeutet hier, dass die Nutzer der Klassen zu 100% von der Singleton Klasse abhängig sind, die Implementierung ist bekannt und damit sind alle Nutzer von ihr abhängig, nicht von einem Interface welche die Implementierung abstrahiert.

Singletons sind sehr schlecht wenn es um das schreiben von Unittests geht, da man sie nicht ersetzen kann.

Jedesmal wenn man ein Singleton einsetzt, nur um von "überall" auf die klasse zugriff zu haben, missbraucht man das Muster, deswegen wird es heute als "Anti-Pattern" gehandelt.
Saubere Anwendung des Singleton Patterns: Man will sicherstellen dass es nur eine einzige Instanz einer Klasse gibt, wie oft geht es einem wirklich nur darum?

Als Alternative bietet sich in so einem Falle eine sog. Registry an, allerdings ist die Verwaltung so einer Registry ohne zus. Framework (Spring!) nicht gerade einfach.


----------



## Marco13 (15. Mai 2008)

Hm. Das mit der Implementierung stimmt nicht sooo 100%ig. Eine "Alternative" oder in gewisser Hinsicht(!) "analog" zum Singleton wäre ja eine Klasse, in der ALLES statisch ist. (Eigentlich ist Objektorierntierte Programmierung ja eh für die Füße - C rules    :wink: ). Bei einem Singleton kann man sich im Gegensatz dazu aber noch aussuchen, welche Instanz zurückgegeben werden soll. D.h. bei einem Singleton kann man mit "getInstance" ein Objekt einer Klasse zurückgeben, bei der Methoden überschrieben (und damit eben _andres_ implementiert) sind. 
Trotzdem schränkt die pauschale und Bedenkenlose Verwendung von Singletons als RAD-Krücke die Flexibilität u.U. erheblich ein.


----------



## maki (15. Mai 2008)

Sicher Marco, 

wenn man nicht vom Singleton/statische Methoden an sich abhängig ist und dieses dann nur die Implementierung eines ServiceProviderInterfaces (tolles Wort, kann bald Anzug & Krawatte anziehen und für große Consulting Firmen arbeiten rofl) zurückgibt welche ich dann benutze, ist es wieder flexibel.

Problematisch ist es, wenn zB. die DaoFactory als Singleton angelegt wurde.


----------



## SilentBob (15. Mai 2008)

Also ich hab jetzt ein JFrame mit 2 JTabbedPanes und Singleton in den beiden Klassen drin. Klappt super, keine X objekte mehr herumschieben, was sehr unübersichtlich ist etc Danke euch!


----------



## maki (15. Mai 2008)

SilentBob hat gesagt.:
			
		

> Also ich hab jetzt ein JFrame mit 2 JTabbedPanes und Singleton in den beiden Klassen drin. Klappt super, keine X objekte mehr herumschieben, was sehr unübersichtlich ist etc Danke euch!


Du hast aber schon mitgelesen, oder?


----------



## diggaa1984 (15. Mai 2008)

nochmal ne frage zum HighCoupling:

wenn ich es also nicht per singelton löse, und stattdessen eine referenz rumreiche per _setDataSource(Object source)_ ist das dann besser? ... ich muss dann quasi aber immer auf die jeweilige Datenklasse casten (die mal Singleton war), oder ist ein _setDataSource(DataClass source)_ genauso gut? ... ersteres wäre ja unabhängiger was die Methodenaufrufe angeht, aber der Mehraufwand existiert dann beim casten.


----------



## maki (15. Mai 2008)

Wie kommst du auf casten?


----------



## diggaa1984 (15. Mai 2008)

na nur wenn ich n Object im Parameter hab, müsste ich dann auf die Datenklasse casten um deren Methoden zu haben? oder fehlt mir grad jegliches Grundwissen?


----------



## maki (15. Mai 2008)

Wieso Object?

Nenne die Klasse doch beim Namen, oder besser, das Interface...


----------



## diggaa1984 (15. Mai 2008)

mit Object wäre ich bei Aufrufen flexibler was das übergebene objekt angeht, da müsst ich nur den code in der methode selbst anpassen, bei nem expliziten klassennamen muss ich bei ner aenderung (andere datenklasse) alle aufrufe aendern


----------



## maki (15. Mai 2008)

> mit Object wäre ich bei Aufrufen flexibler was das übergebene objekt angeht, da müsst ich nur den code in der methode selbst anpassen,


Das sollte ein Scherz sein, richtig?



> bei nem expliziten klassennamen muss ich bei ner aenderung (andere datenklasse) alle aufrufe aendern


Mit einem Interface hast du dieses Problem eben nicht mehr.

Vielleicht fehlen dir wirklich noch die Grundlagen (Vererbung, Polymorphie, etc.).


----------



## diggaa1984 (15. Mai 2008)

willst mir grad damit sagen, das man Object als Parameter auch verhindern sollte? werd aus deiner antwort net schlau ^^


----------



## maki (15. Mai 2008)

Object

Die Basisklasse für alle Objekte.

Viel zu allgemein, deine "Datenklasse" hat doch irgendeine Schnittstelle, lagere diese in ein Interface aus, lass deine Datenklasse dieses Interface implementieren und die Nutzer sollten nur das Interface erwarten.


----------



## SilentBob (15. Mai 2008)

maki hat gesagt.:
			
		

> SilentBob hat gesagt.:
> 
> 
> 
> ...



teilweise ja und mir hilft das Singleton, bin ich jetzt auf der falschen Fährte oder was?


----------



## diggaa1984 (15. Mai 2008)

im prinzip gehts darum das singleton ne schlechte lösung ist, auch wenns noch so toll funktioniert


----------



## SilentBob (15. Mai 2008)

diggaa1984 hat gesagt.:
			
		

> im prinzip gehts darum das singleton ne schlechte lösung ist, auch wenns noch so toll funktioniert



öhm was soll ich sonst nehmen? Bei 8 JTabbedPanes in jedem Konstruktor 3 objekte durchreichen und dann noch methoden von objekten in Konstruktor einer anderen Klasse aufrufen, wenn das objekt noch nicht mal erzeugt wurde... wie soll man das sonst machen?
  ???:L


----------



## Marco13 (15. Mai 2008)

Solange niemand weiß, was du schreibst, weiß man auch nicht, wie man es "besser" modellieren könnte (ob man das wissen will, und ob man sich darüber Gedanken machen will, ist nochmal was anderes ... also ggf. nicht enttäuscht sein). Die Beantwortung der Frage "wie soll man das sonst machen?" ist eben genau das, wofür man so lange lernt und dann die dicke Kohle kriegt    :wink: 
Drei Objekte "manuell" an ein TabbedPane zu übergeben ist ncht schlimm. Notfalls kann man die Objekte auch nochmal in einem übergeordneten Objekt zusammenfassen. Wie die Objekte sich untereinander kennen müssen, musst du aber wissen...


----------



## byte (15. Mai 2008)

Normalerweise kennt eine TabbedPane (oder eine beliebige GUI-Komponente) maximal einen Controller. Ohne Details zu kennen, vermute ich mal, dass Dein MVC-Konzept entweder verbesserungswürdig oder gar nicht existent ist.


----------



## SilentBob (16. Mai 2008)

byto hat gesagt.:
			
		

> Normalerweise kennt eine TabbedPane (oder eine beliebige GUI-Komponente) maximal einen Controller. Ohne Details zu kennen, vermute ich mal, dass Dein MVC-Konzept entweder verbesserungswürdig oder gar nicht existent ist.



wie dem auch sei, mein Problem ist siehe anfangsposting, dass ich z.b. 2 Klassen habe.

Klasse A und Klasse B. In dem Konstruktor von Klasse A rufe ich objekt b auf was aber noch net existieren kann, da Klasse A vor Klasse B instanziiert wird.  KLasse B hat nun ein a objekt mit ner methode am laufen im Konstruktor, daher muss KLasse B nach Klasse A instanziiert sein. Wie löse ich das Problem?


----------



## ms (16. Mai 2008)

SilentBob hat gesagt.:
			
		

> ...z.b. 2 Klassen habe.
> 
> Klasse A und Klasse B. In dem Konstruktor von Klasse A rufe ich objekt b auf was aber noch net existieren kann, da Klasse A vor Klasse B instanziiert wird.  KLasse B hat nun ein a objekt mit ner methode am laufen im Konstruktor, daher muss KLasse B nach Klasse A instanziiert sein. Wie löse ich das Problem?


Kannst du bitte genau diese Erklärung mal als kurzes Codebeispiel posten.
Ich blicke bei deiner Beschreibung nicht ganz durch.

ms


----------



## byte (16. Mai 2008)

SilentBob hat gesagt.:
			
		

> byto hat gesagt.:
> 
> 
> 
> ...


Bei bidirektionaler Referenzierung musst Du den Zyklus aufbrechen. Du kannst z.B. die Referenzen aus den Konstruktoren entfernen und stattdessen per Setter setzen. A.setB() setzt dann direkt in A die Referenz auf B und in B die Referenz auf A.


----------



## SilentBob (16. Mai 2008)

```
Bei bidirektionaler Referenzierung musst Du den Zyklus aufbrechen. Du kannst z.B. die Referenzen aus den Konstruktoren entfernen und stattdessen per Setter setzen. A.setB() setzt dann direkt in A die Referenz auf B und in B die Referenz auf A.
```

schon längst probiert hilft aber auch nicht, denn das objekt a führt eine methode von objekt b in dem Konstruktor von A aus.

A a = new A(); //Bereits hier wird b benötigt um daten einzulesen. doch b wird erst später mit setA(b); gereicht, kann also nicht funktionieren

B b = new B();

a.setA(b);


----------



## ms (16. Mai 2008)

Warum muss das Lesen unbedingt im Konstruktor erfolgen?

ms


----------



## maki (16. Mai 2008)

Hört sich an, als ob die Zuständigkeiten nicht ganz sinnvoll über die 2 Klassen verteilt wurden.


----------



## SilentBob (16. Mai 2008)

So hier ein Codebeispiel bzw. auszug...:



*Main Klasse:*



```
public class MainWindow extends JFrame
{    
   static final long serialVersionUID = 1L;   
   private JTabbedPane jtp = new JTabbedPane();   
   
   public MainWindow() throws IOException
   {
	  super("Test");  
   
      jtp.addTab("Invoice", InvoicePanel.getInstanz());   
      jtp.addTab("Settings", SettingsPanel.getInstanz()); 
    
      add(jtp); 
      
      setResizable(false);      
      setSize(400,400);
      setLocationRelativeTo(null);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     
      setVisible(true);	
      
   }
       
   public static void main(String []args) throws Exception
   {  
	      
	      EventQueue.invokeLater(new Runnable()
	      {
		      public void run()
		      {	      
				try 
				{ 				
					new MainWindow(); 
				}
				catch (IOException e)
				{				
					e.printStackTrace();
				}	                    
		      }
	      });  	      
   }
}
```


*1. Tab: InvoicePanel*



```
public class InvoicePanel extends JPanel
{	 	
	private static final long serialVersionUID = 1L;
	private static InvoicePanel invoice;

	private InvoicePanel()
    {   
		SettingsControl.getInstanz().loadXMLData(); // lädt xml-Daten aus einer XML-Datei in 2 JComboBoxen die sich in SettingsPanel befinden
        SettingsPanel.getInstanz().copyXMLData(); // kopiert alle String-Daten aus den 2 JComboBoxen, die sich in SettingsPanel befinden in die 2
                                                  // JComboBoxen die sich in InvoicePanel befinden. Dies hat den Grund, dass in SettinsPanel Daten
                                                  // added/removed werden können. Während in InvoicePanel sollen nur Daten ausgewählt werden können.
 Innerhalb von SettingsControl greife ich ja auf SettingsPanel zu was noch gar nicht existiert..., 
da SettingsPanel in MainWindow nach InvoicePanel erstellt wird... Henne - Ei fällt mir dazu nur ein ;-)
    }
	
	// Die Klasse SettingsControl + SettingsData poste ich hier nicht, aus Zeit und anderen Gründen ;-)
	    
    public static InvoicePanel getInstanz()
    {    	 
    	if(invoice == null)
      	{
    		invoice = new InvoicePanel();
      	}
    	return invoice;
    }    
}
```


*2.Tab SettingsPanel*

```
public class SettingsPanel extends JPanel
{	 
	
	private static final long serialVersionUID = 1L;
	private static SettingsPanel settings;

	private SettingsPanel()
    {  		
    }
	    
    public static SettingsPanel getInstanz()
    {    	 
    	if(settings == null)
      	{
    		settings = new SettingsPanel();
      	}
    	return new SettingsPanel();
    }    
}
```


----------



## ms (16. Mai 2008)

```
public class MainWindow extends JFrame
{   
   public MainWindow() throws IOException
   {
      super("Test"); 

      XmlDaten xmlDaten = leseXmlDaten();
      
      InvoicePanel invoicePanel = new InvoicePanel();
      invoicePanel.setDaten(xmlDaten);

      SettingsPanel settingsPanel = new SettingsPanel();
      settingsPanel.setDaten(xmlDaten);

      jtp.addTab("Invoice", invoicePanel);   
      jtp.addTab("Settings", settingsPanel);
   
      add(jtp);
     
      ...     
   }

   private XmlDaten leseXmlDaten() {
   
      // ... hier werden die Daten gelesen und zurückgegeben

      return ...
   }

}
```

edit: InvoicePanel und SettingsPanel müssen natürlich mit den XmlDaten umgehen können.
Noch besser wäre es wenn man eine Referenz auf eine Modelklasse mitgibt, damit die Actions gleich darauf arbeiten können.

ms


----------



## SilentBob (16. Mai 2008)

OK ich habs jetzt so gelöst:

der Aufruf untenstehender Methoden erfolgt in der MainWindow Klasse

      jtp.addTab("Invoice", InvoicePanel.getInstanz());   
      jtp.addTab("Settings", SettingsPanel.getInstanz()); 



```
SettingsControl.getInstanz().loadXMLData();
      SettingsControl.getInstanz().copyXMLData();
      InvoicePanel.getInstanz().readStartDirectory();
      InvoicePanel.getInstanz().readStartFiles();
```

obige Methoden müssen in dieser Reihenfolge gelesen werden da z.B. je nach gesetztem Start Directory bestimmte Files gelesen werden etc...

trotzdem würde mich interessieren wie Ihr sowas löst!?


----------



## ms (16. Mai 2008)

SilentBob hat gesagt.:
			
		

> trotzdem würde mich interessieren wie Ihr sowas löst!?


Siehe einen Beitrag weiter oben.

Merkst du wirklich nicht, dass zwischen

```
SettingsControl.getInstanz().loadXMLData();
SettingsControl.getInstanz().copyXMLData();
```
und

```
SettingsControl settingsControl = new SettingsControl();
settingsControl.loadXMLData();
settingsControl.copyXMLData();
```
ein kleiner aber bedeutender Unterschied besteht?

ms


----------



## SilentBob (16. Mai 2008)

ms hat gesagt.:
			
		

> SilentBob hat gesagt.:
> 
> 
> 
> ...



Da gibts schon einen Unterschied  :wink: 

Doch das ist ja dein Code woher sollte ich den Unterschied also kennen ???

auf beide Methoden loadXXX und copyXXX wird mit einem Objekt zugegriffen. Beim 1. mal über ein objekt einer Singleton Klasse beim 2. mal über eine objekt einer normalen Klasse eben.

Sonst noch was?


----------



## SilentBob (16. Mai 2008)

```
SettingsControl.getInstanz().saveXMLData();
```

dies rufe ich in der SettingsPanel Klasse auf, würde ich in MainWindow dein code:


```
SettingsControl settingscontrol = new SettingsControl()
```
 benutzen würde das nicht gehen oder ich machs wieder so, dass ich das settingscontrol objekt durchreiche an den Konstruktor von SettingsPanel etc...

was meinst du?


----------



## ms (16. Mai 2008)

Für die Ausführung in deiner Methode macht es keinen Unterschied, in beiden Fällen wird das selbe Ergebnis erreicht.
In deinem Fall aber gibst du explizit an, woher das Objekt kommt => high coupling.
Und darum geht es die ganze Zeit.

ms


----------



## SilentBob (16. Mai 2008)

ms hat gesagt.:
			
		

> Für die Ausführung in deiner Methode macht es keinen Unterschied, in beiden Fällen wird das selbe Ergebnis erreicht.
> In deinem Fall aber gibst du explizit an, woher das Objekt kommt => high coupling.
> Und darum geht es die ganze Zeit.
> 
> ms



Aus ner PDF geklaut...:




> If two classes depend closely on
> many details of each other, we say
> they are tightly coupled.



so siehts ja bei mir aus... sprich das ganze muss gelockert werden -> ich nenns mal low coupling ^^.

Wo gebe ich an woher das Objekt kommt, kannst du mir die Zeile zeigen? Nicht das ich dir net glaube ich weiß es einfach nicht hehe. Ein Objekt kommt daher wo es erzeugt wird und in beiden Fällen erzeuge ich das settingscontrol in der MainWindow Klasse.


----------



## maki (16. Mai 2008)

Da ist das "high coupling": getInstanz()


----------



## ms (16. Mai 2008)

SilentBob hat gesagt.:
			
		

> Aus ner PDF geklaut...:
> 
> If two classes depend closely on
> many details of each other, we say
> they are tightly coupled.



Welches PDF war das denn?



			
				SilentBob hat gesagt.:
			
		

> so siehts ja bei mir aus... sprich das ganze muss gelockert werden -> ich nenns mal low coupling ^^.


Bingo, Low coupling ist das Stichwort.



			
				SilentBob hat gesagt.:
			
		

> Wo gebe ich an woher das Objekt kommt, kannst du mir die Zeile zeigen? Nicht das ich dir net glaube ich weiß es einfach nicht hehe. Ein Objekt kommt daher wo es erzeugt wird und in beiden Fällen erzeuge ich das settingscontrol in der MainWindow Klasse.


Schau dir nochmal mein Beispiel an.
Dort werden in der main-Methode zuerst die Daten geladen und dann den Panels übergeben.
Die Panels selber haben jeweils nur einen Setter und eine Instanzvariable für die Daten.
Sie (die Panels) kümmern sich also nicht selbst darum woher die Daten kommen sondern erwarten dass sie gesetzt werden, von wem auch immer. Damit hast du insofern eine lose Kopplung, als dass du dieses Panel auch in einem komplett anderen Programm verwenden könntest, eine eigenständige Komponente sozusagen.
Derjenige, der diese Komponenten zu einem Programm zusammenfügt muss natürlich dafür sorgen, dass die Daten gesetzt werden.

ms


----------



## SilentBob (14. Mai 2008)

Hallo,

Ich habe einen JFrame mit bisher 6 TabbedPanes drin, könnten auch bis zu 10 werden.

Nun haben diese 6 GUI Klassen zur Unterscheidung namen wie xxxView während die dazugehörigen Klassen mit den Methoden xxxControl heißen und evtl. gibts noch xxxModel Klassen die Daten aufnehmen.

Nun sind das ganze ca. 15 Klassen. Jede der Klasse greift mehr/weniger auf andere Klassen zu. Nun habe ich natürlich das WirrWarr, dass ich die erzeugten Objekte der GUI KLassen oder die Objekte der Control Klassen überall hindurchreichen muss, denn ein 2. Objekt der GUI Klasse geht nicht, da ich sonst einen NullPointer  bekomme. Das ganze sieht dann natürlich nicht so elegant aus und viele KLasse haben 3 Parameter im Konstruktor.

Nun frage ich mich ob es nicht ideal wäre das Singleton Pattern hier anzuwenden:

1. damit objekte auch sicher nur einmal erzeugt werden und ich nicht immer darauf achten muss ja das Objekt richtig weiterzugeben etc

2. damit ich eine angebliche so las ich es GLOBALE Stelle habe wo ich das Objekt abholen kann. Wäre super geschickt, wenn ich nicht immer von hir nach da und dort das Objekt reiche...

3. und das Single-Objekt wird nur erstellt wenns benötigt wird, spart Ressourcen.

Ist das Singleton ok für diesen Anwendungsfall? was denkt Ihr? Hat mir vielleicht jemand gute Links mit Anwendungsfällen dieser Komplexität?


----------



## SilentBob (16. Mai 2008)

> Welches PDF war das denn?



http://www.google.de/url?sa=t&ct=re...Ya3T8Ge32L5qpI9-A&sig2=XwSUSTjFD-d8M_YPlZhQBA
]


> Schau dir nochmal mein Beispiel an.


 ähm sorry jetzt weiß ich erst von was du redest... dein bsp auf seite 3 habe ich vor lauter posts gar nicht gesehen    :wink:


----------



## SilentBob (16. Mai 2008)

ms hat gesagt.:
			
		

> ```
> public class MainWindow extends JFrame
> {
> public MainWindow() throws IOException
> ...



müsste das nicht 
	
	
	
	





```
invoicePanel.setDaten(leseXmlDaten())
```
 heißen ? Das X ist einmal groß und einmal kleingeschrieben, daher verwirrend.

Naja eine leseXMLDAten Funktion in einer View sprich JFrame orientiert sich aber nicht sehr start an der Trennung von View und Model oder? 



> Noch besser wäre es wenn man eine Referenz auf eine Modelklasse mitgibt, damit die Actions gleich darauf arbeiten können.



meinst du mit Referenz die Instanz meiner SettingsData Klasse wo alle xml Daten drin sind? yo diese Referenz wäre dann in der leseXmlDaten() methode.


----------



## ms (16. Mai 2008)

Alle X sind richtig.

Eine Methode hält in dem Sinn keine Referenzen so wie es Objekte tun.
Ich verstehe deine Frage nicht ganz.



> invoicePanel.setDaten(leseXmlDaten())


Du willst die Daten doch auch im SettingsPanel haben, oder?
Also einmal Lesen und die Referenz den beiden Panels die Referenz übergeben.

ms


----------



## SilentBob (16. Mai 2008)

oh man meine Augen...

Ich dachte: 
	
	
	
	





```
XmlDaten xmlDaten = leseXmlDaten();
```

das heißt 
	
	
	
	





```
XmlDaten xmlDaten = new XmlDaten();
```

jetzt verstehe ich erst den Zusammenhang bzw. warum das eine X groß/klein ist hehe

1.) Ich nehme an, dass deine Methode leseXmlDaten() meiner methode loadXMLData() entspricht, wenn ja dann habe ich zwar eine Referenz in dem objekt xmlDaten und übergebe das objekt dem InvoicePanel/SettingsPanel doch dann bräuchte ich ja noch getxx Methoden in beiden Panel-Klassen die das objekt auslesen und die daten in die JCBoxen schreiben richtig?

2.) Was mich wundert ist, dass du die leseXmlDaten() methode in die View schreibst? OK es gibt 1000 verschiedene anwendugsarten und spezielle Problemfälle ich bin auch der Meinung, dass man MVC etc nicht in jedes Schema pressen kann ;-)


----------



## SilentBob (16. Mai 2008)

So das einlesen in beide JComboboxen geht erstmal, ob es so ist wie dus gerne hättest bin mir net 100% sicher...



```
public class MainWindow extends JFrame
{    
   static final long serialVersionUID = 1L;   
   private JTabbedPane jtp = new JTabbedPane();   
   private SettingsData settingsdata = new SettingsData();
   public MainWindow() throws IOException
   {
	  super("Test");  
   
	  SettingsData settingsData = loadXMLData(); 
	  
	  InvoicePanel invoicePanel = new InvoicePanel(); 
	  invoicePanel.setDaten(settingsData); 	  
	  
	  SettingsPanel settingsPanel = new SettingsPanel();
	  settingsPanel.setDaten(settingsData); 
	  
      jtp.addTab("Invoice", invoicePanel);  
      jtp.addTab("Settings", settingsPanel); 
    
      add(jtp); 
      
      setResizable(false);      
      setSize(400,400);
      setLocationRelativeTo(null);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     
      setVisible(true);	
      
   }
   
   public SettingsData loadXMLData()
	{ 		
		try
		{ 
           JAXBContext jc = JAXBContext.newInstance(SettingsData.class);
           Unmarshaller um = jc.createUnmarshaller ();           
	       Object o = um.unmarshal(new FileInputStream("test.xml"));
	       settingsdata = (SettingsData) o; 	       
	         
      }
	   catch (Exception e)
	   {
       e.printStackTrace (); 
      }
	   
	   return settingsdata;
	   
	}
       
   public static void main(String []args) throws Exception
   {  
	      
	      EventQueue.invokeLater(new Runnable()
	      {
		      public void run()
		      {	      
				try 
				{ 				
					new MainWindow(); 
				}
				catch (IOException e)
				{				
					e.printStackTrace();
				}	                    
		      }
	      });  	      
   }
}
```



```
public class InvoicePanel extends JPanel
{	 	
	private static final long serialVersionUID = 1L;
    JComboBox jcb = new JComboBox();

	public InvoicePanel()
    {   
		setLayout(null);
		add(jcb);		
		jcb.setBounds(0,0,200,30);
    }
	
	public void setDaten(SettingsData settingsData)
	{
		for(int i = 0 ; i < settingsData.getListCurrencyFormat().size() ; i++)
        {
        	jcb.addItem(settingsData.getListCurrencyFormat().get(i));	        	
        }		
	}	   
}
```



```
public class SettingsPanel extends JPanel
{	 	
	private static final long serialVersionUID = 1L;
	JComboBox jcb = new JComboBox();

	public SettingsPanel()
    {  		
		setLayout(null);
		add(jcb);		
		jcb.setBounds(0,0,200,30);
    }
	
	public void setDaten(SettingsData settingsData)
	{
		for(int i = 0 ; i < settingsData.getListCurrencyFormat().size() ; i++)
        {
        	jcb.addItem(settingsData.getListCurrencyFormat().get(i));	        	
        }		
	}	    
}
```


Was ich nicht ganz verstehe ist , warum kann ichs net so machen:


```
// fällt weg, da methodenaufruf in methode eh settingsData zurückgibt...
//SettingsData settingsData = loadXMLData(); 
	  
InvoicePanel invoicePanel = new InvoicePanel(); 
invoicePanel.setDaten(loadXMLData()); 	  
	  
SettingsPanel settingsPanel = new SettingsPanel();
settingsPanel.setDaten(loadXMLData());
```


----------



## SilentBob (16. Mai 2008)

> Damit hast du insofern eine lose Kopplung, als dass du dieses Panel auch in einem komplett anderen Programm verwenden könntest, eine eigenständige Komponente sozusagen.
> Derjenige, der diese Komponenten zu einem Programm zusammenfügt muss natürlich dafür sorgen, dass die Daten gesetzt werden.



Ok solangsam kapier ichs... obiges heißt also weil ich die setDaten(...) Methode benutze ist die Panel GUI unabhängig, denn man kann muss aber net diese Methode aufrufen, daher kann ich den panel auch in einem anderen Programm nutzen sozusgen, da keine direkte Abhängigkeit zu den xml Daten besteht. Ok würde ich den Panel als eigentständige Komponente nutzen und rufe die setDaten nicht auf sprich sie wird nicht benötigt in dem anderen Programm sollte ich sie ja löschen da Speicherverschwendung auch wenn sie net aufgerufen wird oder?


----------



## SilentBob (17. Mai 2008)

was ich mich jetzt auch noch frage ist:

Ich habe mehrere Klassen die Informationen aus der xml datei benötigen. Diese Informationen sind in dem settingsData Objekt drin und werden in die GUI sprich SettingsPanel geschrieben. Soll ich nun die Infos direkt aus dem Objekt settingsData lesen oder auf die GUI zugreifen und hier auslesen, wie handhabt man das am Besten allgemein?


----------



## SilentBob (18. Mai 2008)

wäre nett wenn mir jemand noch die letzten Fragen beantworten könnte.


----------



## diggaa1984 (18. Mai 2008)

rein prinzipiell neige ich dazu die daten ausschließlich aus der datenquelle zu beziehen, die GUI holt sie sich und zeigt nur an, und is mit ausnahme der nutzereingaben nicht für datenbereitstellung konzipiert, also in meinen programmen


----------



## ms (19. Mai 2008)

SilentBob hat gesagt.:
			
		

> Ok würde ich den Panel als eigentständige Komponente nutzen und rufe die setDaten nicht auf sprich sie wird nicht benötigt in dem anderen Programm sollte ich sie ja löschen da Speicherverschwendung auch wenn sie net aufgerufen wird oder?


Du willst die Methode setDaten(...) in einem anderen Programm löschen weil du sie dort nicht brauchst?
Wenn du prinzipiell so vor gehst dann müsstest du ja auch alle nicht benötigten Methoden aus der Java-Api löschen. :autsch: 
Oder meinst du was anderes?



			
				SilentBob hat gesagt.:
			
		

> Ich habe mehrere Klassen die Informationen aus der xml datei benötigen. Diese Informationen sind in dem settingsData Objekt drin und werden in die GUI sprich SettingsPanel geschrieben. Soll ich nun die Infos direkt aus dem Objekt settingsData lesen oder auf die GUI zugreifen und hier auslesen, wie handhabt man das am Besten allgemein?


Mit dem MVC-Pattern.

ms


----------



## voidee (20. Mai 2008)

Ich nehme mal Bezug auf das Ursprungsposting, ohne die restlichen Antworten alle durchzuarbeiten:

grundsätzlich denke ich, dass eine Trennung von View und Mode und Controller eine sehr sinnvolle Sache ist (MVC hat was). Das Problem ist, dass man das schön durchhält, wenn man ein oder zwei GUI's hat. Bei 6 bis 10 wächst das ganz ordentlich an. Das werden sehr viele Klassen. Aber was macht das? Das ist vielleicht für den Entwickler oder für einen selbst, wenn man 6 Monate später reinschaut zunächst ein bisschen viel, aber im Endeffekt bleiben es 3 grob 3 Klassen je GUI. 

Stellt sich die Frage der Übersichtlichkeit.

Bleibt der Quellcode übersichtlicher wenn man ein "Singleton" verwendet? Ich denke wenn man sich mit dem Grundgedanken, was das Singleton-Pattern soll, auseinandersetzt, wird man herausfinden, dass Singleton nicht die Lösung ist. 
Ein Singleton System soll sicherstellen, dass in einer Java-Virtual-Machine nur *eine* Instanz des Objekts existiert. Als Anwender möchte ich aber bei einer GUI ruhig mal ein zweites oder drittes Fenster öffnen. das Singleton würde mir das verbieten. 

Deshalb würde ich empfehlen, dass man eine "Main" Klasse entwickelt, die alle Sub-GUIS (JPanels?) instanziiert. Im Konstruktur wird bei meinen Lösungen im Regelfall die Mainklasse mitgegeben. Kommunkation erfolgt über das Listener-Konzept. Dadurch werden aber noch ein paar zusätzliche Klassen notwendig, aber man sollte bedenken, dass Progrmmierung nicht nur aus Quellcode besteht. Javadoc - und das ist echt eine tolle Sache - gehört meines Erachtens auch dazu.


----------

