# Klassenaufbau bei komplexerer GUI Anwendung



## P@u1 (24. Jan 2012)

Hallo zusammen,

ich überlege schon seit längeren, wie man eine komplere GUI-Anwendung aufbaut (nicht Java-spezifisch). 
Ich habe mir MVC angesehen, allerdings findet das so wie ich das verstehe eher auf Komponentenebene statt, also das ein TreeView z.B. aus einem Model und einer View besteht.
Das ist allerdings nicht wirklich, wonach ich suche.

Mir geht es eher darum, wie die Gesamtanwendung aufgebaut wird.

Sinnvoll wäre sicherlich eine Trennung in
- Präsentationsschicht
- Logikschicht
(+ evtl. Datenschicht oder sowas)

Machen wir mal ein Beispiel:
Meine graphische Oberfläche besteht aus einem Hauptfenster, aus 5 Widgets besteht.
Jedes dieser Widgets kann jetzt wiederrum aus einem Modell und einer View bestehen.
Bisher habe ich keine Controller verwendet.

Die Struktur sieht dann so aus:


```
MainWindow
    PlotWidget
    PlotConfigWidget
    VitalsWidget
    SensorInformationWidget
    RecordWidget
```

Wie greife ich nun "von außen" auf die Models zu?
Erstelle ich dafür eine Wrapperklasse, die alle Models beinhaltet, von der aus ich Zugriff auf die models habe?

Z.B. muss das PlotConfigWidget (oder sein Controller, der im Moment noch nicht exisitert), wenn man dort etwas ändert das Model des PlotWidgets verändern.

Wie initialisiere ich jetzt die ganze graphische Oberfläche inkl. Models? Von wo kann man auf die Models zugreifen?

Ich habe recht viel im Internet gesucht zum (Klassen-)Aufbau von (komplexeren) GUI-Anwendungen, aber nicht wirklich was gefunden. Es wird eigentlich immer nur darauf eingegangen, wie man mit GUI-Framework X bestimmte sachen macht, das ist aber nicht was ich suche. 
Kennt ihr vielleicht ein gutes Buch oder Artikel oder sonstwas dazu? Kann mit Java, C# oder C++ sein.

Vielen Dank schonmal für eure Hilfe!


----------



## Michael... (24. Jan 2012)

P@u1 hat gesagt.:


> Ich habe mir MVC angesehen, allerdings findet das so wie ich das verstehe eher auf Komponentenebene statt, also das ein TreeView z.B. aus einem Model und einer View besteht.


Nein, das kann auch auf Applikationsebene eingesetzt werden. Es ist ja beliebig skalierbar und beschreibt ja nur die Trennung/Kommunikation zwischen Präsentations-, Logik- und Datenschicht.


----------



## P@u1 (24. Jan 2012)

Danke für den Hinweis.

Wie setzt man sowas auf Applikationsebene dann praktisch um?

Erstelle ich dann eine Art Meta-Model, das alle models die irg0endwo verwendet werden als attribute hat und damit leichten zugriff auf die models ermöglicht?
Oder Eventuell hierarchisch?

Ich stelle mir das dann z.B. so vor:


```
public class MetaModel
{
   private PlotModel plotModel;
   private PlotConfigModel plotConfigModel;
   private VitalsModel vitalsModel;
   private SensorInformationModel sensorInformationModel;
   private RecordModel recordModel;

   //getter methoden
}

public class MainWindow
{
    private PlotWidget plotWidget;
    private PlotConfigWidget plotConfigWidget;
    private VitalsWidget vitalsWidget;
    private SensorInformationWidget sensorInformationWidget;
    private RecordWidget recordWidget;

   public MainWindow(MetaModel model)
   {
       this.plotWidget = new PlotWidget(model.getPlotModel());
       this.plotConfigWidget = new PlotConfigWidget(model.getPlotConfigModel());
      //usw.
   }

   public static void main(String[] args)
   {
       MetaModel model = new MetaModel();
       MainWindow window = new MainWindow(model);
   }
}
```

Was haltet ihr davon? Ist sowas üblich oder eher nicht? Gibt es Verbesserungsmöglichkeiten?

P.S.: Und wie siehts mit Büchern o.ä. dazu aus, kennt ihr was gutes?


----------



## Michael... (24. Jan 2012)

Tendenziell würde ich hierarchisch verschachteln. Eventuell macht so ein MetaModel Sinn für Models die irgendwie zusammen hängen.
Es ist aber durchaus möglich, dass mehrere Views auf ein gemeinsames Model zugreifen. z.B. könnten sich PlotWidget und PlotConfigWidget ein PlotModel teilen, fall es von den Daten her Sinn macht. Bücher dazu kenne ich keine. Die Grundsätze dazu sollte aber in einem Buch zu Entwurfsmustern zu finden sein.


----------



## P@u1 (24. Jan 2012)

Danke für deine Hilfe!

Zu Entwurfsmustern habe ich bisher eigentlich nur Entwurfsmuster von Kopf bis Fuß gelesen. MVC wird da behandelt, aber eher an einem kleinen Beispiel und es wird nicht gezeigt, wie man das jetzt in einem größeren Maßstab benutzt.

Das mit gemeinsamen Model von PlotWidget und PlotConfigWidget macht durchaus Sinn.

Im Moment gibts noch nicht genug "Ebenen" um es hierarschich zu lösen. Es gibt also erst das MainWindow und dann die Widgets dadrin.

Viel anderes als das mit dem Metamodel fällt mir nicht ein, gibts da noch sinnvolle Alternativen?
Auf die Models muss von einigen Stellen zugegriffen werden, und ich dachte, dass das Metamodel dann dabei hilft. Man braucht sich nur die eine Referenz zu speichern und kommt von da dann zu jedem Model, das man braucht.


----------



## Michael... (24. Jan 2012)

Auf ein Model wird von genau zwei Stellen aus zugegriffen. Einmal Controller und einmal (pro) View.
Was Du mit dem MetaModel bezweckst ist mir nicht ganz klar. Da man in dem Fall ja alles auch direkt in ein Model stecken kann. Die View sollte nur wissen, dass es ein Model gibt, und am besten auch nur die über ein Interface definierten Schnittstellen kennen. Wenn diese erst einmal in einem MetaModel zweimal links und einmal rechts zu ihrem Model kommt, verlierst Du ja die lose Kopplung die durch das MVC angestrebt wird. Clustern macht dann auf Seite des Controllers. Einen "Meta" Controller der den PlotController, RecordController... steuert.


----------



## P@u1 (24. Jan 2012)

Bisher habe ich Controller ganz rausgelassen, daher kommt dann meine Idee eine Metamodel zu verwenden.
Ich hab noch nicht so 100% verstanden, wie das mit dem Controller funktioniert.
Dazu habe ich verschiedene Sachen gelesen, die sich teilweise widersprechen:

Gelesen habe ich z.B. von folgenden Ansätzen:
-Der Controller wird von der View als Strategie verwendet um auf eingaben zu reagieren
-Der Controller wird mit in die View integriert

Ich muss von Außen im wesentlichen mindestens diese 2 sachen machen:
-Ein paar SQL-Queries absetzen, die das PlotModel verändern
-Ein paar Werte umsetzen, die vom SensorInformationModel dargestellt werden

Setze ich das dann bei den Models oder über einen Controller? Wenn ichs über einen Controller von außen setze, dann ist der Controler ja zumindest nicht mehr nur die Strategie einer View.
Wie würden dann hier die Controller aussehen?


----------



## Michael... (24. Jan 2012)

P@u1 hat gesagt.:


> Dazu habe ich verschiedene Sachen gelesen, die sich teilweise widersprechen:
> 
> Gelesen habe ich z.B. von folgenden Ansätzen:
> -Der Controller wird von der View als Strategie verwendet um auf eingaben zu reagieren
> -Der Controller wird mit in die View integriert


Inwiefern siehst Du hier einen Widerspruch?
Bei kleineren Applikationen ist es durchaus sinnvoll und üblich den Controller in die View oder umgekehrt zu integrieren.


P@u1 hat gesagt.:


> Ich muss von Außen im wesentlichen mindestens diese 2 sachen machen:
> -Ein paar SQL-Queries absetzen, die das PlotModel verändern


Gemeint ist Daten einer Datenbank zu manipulieren und darauf das PlotModel zu aktualisiern?
Hier könnte es evtl. Sinn machen einen SubController zu implementieren der den Zugriff auf die Datenbank regelt. Hierüber werden Daten in die Datenbank gespielt und das Model aktualisiert.


P@u1 hat gesagt.:


> -Ein paar Werte umsetzen, die vom SensorInformationModel dargestellt werden


Werte umsetzen über die View?


P@u1 hat gesagt.:


> Setze ich das dann bei den Models oder über einen Controller? Wenn ichs über einen Controller von außen setze, dann ist der Controler ja zumindest nicht mehr nur die Strategie einer View.
> Wie würden dann hier die Controller aussehen?


Grundsätzlich hängt das immer vom konkreten Anwendungsfall ab. Hier gibt es kein Schwarz/Weiß. Um da Vorschläge zu machen, müsste man die Zusammenhänge kennen.


----------



## P@u1 (24. Jan 2012)

Michael... hat gesagt.:


> Grundsätzlich hängt das immer vom konkreten Anwendungsfall ab. Hier gibt es kein Schwarz/Weiß. Um da Vorschläge zu machen, müsste man die Zusammenhänge kennen.



Ok, dann werd ich mal ein bischen was erzählen:

Im großen und ganzen geht es dadrum:
Ich kriege Daten über die serielle Schnittstelle, plotte diese und zeige ein paar Werte dazu an.

Die graphische Oberfläche soll im Hauptfenster erstmal einige Plots anzeigen (dafür das PlotWidget), und daneben ein paar Vital- und Sensor-Werte.
Und man kann ein Optionsmenü öffnen, in dem man die serielle Schnittstele konfigurieren kann und die Plots und deren Belegunen bearbeiten kann.
Die Belegung der Plots und deren Optionen werden in einer Datenbank gespeichert.

Bisher habe ich erstmal für die Plots eine Klasse PlotArea erstellt und eine Modelklasse PlotConfigModel.
Für die Vital- und Sensorwerte wollte ich auch noch jeweils ein Model erstellen und Widgets zum anzeigen gibt es schon.
Dann habe ich noch ein Optionsdialog geschrieben, in dem man die Plots konfigurieren kann, da wird auch das PlotConfigModel verwendet.

Das holen der Daten passiert komplett außerhalb der graphischen Oberfläche, aber trotzdem muss ich, sobald ich neue Werte habe die Plotdaten, die Vitalwerte und die Sensordaten ändern, also brauche ich "von außen" Zugriff auf die entsprechenden Models (oder Controller, falls ich solche erstelle).

Hast du vielleicht ein paar Vorschläge, wie ich das ganze in guter Weise umsetzen kann?


----------



## Michael... (24. Jan 2012)

Inwieweit unterscheiden sich die Plot von den Sensor und Vitaldaten? Wenn letzere Bestandteil der Plotdaten sind oder mit diesen zusammenhängen, macht des vielleicht Sinn diese in einem gemeinsamen Model zu halten. Um das oder die Models zu befüllen benötigst Du eine Klasse die von der Seriellen Schnittstelle liest und die Daten ins Model schreibt.
Da die Daten scheinbar nur angezeigt, nicht aber bearbeitet werden sollen, benötigen die Anzeigeobjekte keinen Controller und es reicht aus diese als Observer/Listener am Model zu registrieren.


----------



## P@u1 (24. Jan 2012)

Sensor und Vitaldaten verhalten sich ähnlich: Da ist jeweils nur der neueste wert relevant.
Bei den Plotdaten ist das anders, da brauch man auch die werte die früher waren. Das mit den Plotdaten hab ich mit observer realisiert, da melden sich dann einige Plotkurven an und kriegen neue daten.

Die Sensor und Vitaldaten werden bisher noch nicht an die GUI weitergereicht, das wäre der nächste Schritt.

Die Daten selbst werden nur angezeigt, aber von der GUI aus kann die serielle schnittstelle und die anzeige der plots konfiguriert werden.

Bisher verwende ich wie gesagt nirgendswo einen Controller. 
Siehst du hier irgendwo einen sinnvollen Anweundgsfall für einen Controller?
Ohne Controller würde ich das ganze dann wohl mit dem "Meta-Model" lösen, wenn uns nichts mehr besseres einfällt.
Und für die Vital und Sensordaten mache ich dann wahrscheinlich gar nicht erst ein Model, sondern registriere dann die Anzeigen davon als Observer wie du gesagt hast.


----------



## bygones (25. Jan 2012)

ich halte nicht viel von solchen Meta-Model-Monsterklassen, da eine Stelle zu viel weiss. Diese wird dann einfach ueberall reingereicht oder wahrscheinlich noch als Singleton oder so implementiert.

Sagt dir Dependency Injection etwas ? falls nicht versuch darueber was zu lesen. Jede Klasse sollte nur das Wissen bekommen, womit sie arbeiten kann. Natuerlich ist der "Aufwand" dann etwas groesser das zu organisieren, aber man kann moeglicherweise vorhandene Frameworks ala Guice nutzen.

ein Controller ist vor allem dann stark, wenn es eine bidirektionale verbindung zwischen Model und UI gibt, also wenn in der UI aenderungen ans Model gereicht werden. Nichtsdestotrotz ist es immer sinnvoll eine weitere Schicht zwischen Model und UI zu haben.

Wie gesagt, versuch zu vermeiden so all-wissens-batzen wie das Meta-Model zu nutzen


----------



## P@u1 (25. Jan 2012)

Ich hab mir zu Dependency Injection eben mal was durchgelesen, aber ich finde das im Moment erstmal zu umständlich.



Michael... hat gesagt.:


> Wenn diese erst einmal in einem MetaModel zweimal links und einmal rechts zu ihrem Model kommt, verlierst Du ja die lose Kopplung die durch das MVC angestrebt wird. Clustern macht dann auf Seite des Controllers. Einen "Meta" Controller der den PlotController, RecordController... steuert.



Ich glaube ich habe hier noch ein verständnisproblem:

Das Model stellt ja die Anwendungsdaten und logik da.
Die View ist zum Anzeigen da.
Und der Controller ist die Strategie einer View um Benutzeraktionen zu verarbeiten.

Wenn ich jetzt aber von außerhalb der UI ein Modell ändern will, arbeite ich dann direkt mit dem Modell oder mit einem Controller?
Controller würde da ja eig nich viel Sinn machen, weil es nicht um Benutzerinteraktionen geht, sondern um Daten, die von der seriellen Schnittstelle kommen.
Und wenn ich direkt mit dem Model arbeite, muss ich ja irgendwie von der Klasse, die die serielle Schnittstelle ausliest aus an die Modelle rankommen.
Von dort aus muss ich sowohl auf das Model für die Plotdaten, als auch auf das Model für die Vitaldaten als auch auf das Model für die Sensordaten zugreifen.
Und ohne Eine Containerklasse, die Zugriff auf die Models ermöglicht, weiß ich nicht, wie ich an die Modelle rankommen kann.

Ansonsten könnte mans auch andersrum betrachten, so das diese Modelle eigentlich Teil der Anwendungslogik sein müssten und damit in der Klasse, die die Daten holt erzeugt/gespeichert werden sollte.
Dann muss ich aber trotzdem von der UI aus auf die Modelle zugreifen können..

Irgendwie verwirrt mich das gerade etwas.
Könnt ihr vielleicht eine grobe Klassenstruktur vorschlagen, wie ihr es lösen würdet?


----------



## KrokoDiehl (25. Jan 2012)

Hallo.
Ich finde es schwer darauf zu antworten, weil es doch so allgemein klingt und es - wie bereits erwähnt wurde - keine allgemeingültige Superlösung gibt.
Prinzipiell klingt dein Problem mit den Abhängigkeiten durchaus nach einem Fall für Depency Injection aber es geht natürlich auch ohne.

Wenn es "nur" um den initialen Aufbau bzw. das Anlegen der Objekte und Versorgen mit Daten geht, dann kann man dies weitestgehend ohne Abhängigkeiten gestalten. In Pseudocode etwa so:

```
// z.B. in main() ...
SerielleSchnittstelle sss = new SerielleSchnittstelle();

Controller1 ctrl1 = new Controller1(
        new View1(), new Model1( sss.getDaten() ));
Controller2 ctrl2 = new Controller2(
        new View2(), new Model2( sss.getDaten() ));
Controller3 ctrl3 = new Controller3(
        new View3(), new Model3( sss.getDaten() ));

baueUIauf(ctrl1.getView(), ctrl2.getView(), ctrl3.getView());
```

Wenn die Modelle zur Laufzeit aktualisiert werden müssen wäre eine Frage, wie es ausgelöst wird bzw. wer es macht. So wie ich es verstehe nicht über die UI folglich auch nicht über den Controller. Der Auslöser müsste m.E. alle (betroffenen) Modelle kennen. Um diese Abhängigkeit etwas "dünner" zu machen kann man mit Interfaces arbeiten:

```
public interface Model ...
public class Model1 implements Model ...
```
Damit kann der Auslöser dann mit solchen Referenzen arbeiten. Zum Beispiel so:


```
public class Updater {
    private final List<Model> models;    
    private final SerielleSchnittstelle sss;
 
    public Updater(SerielleSchnittstelle sss) {
        this.sss = sss;
        this.models = new ArrayList<Model>();
    }

    public void addModel(Model model) {
        models.add(model);
    }

    public void update() {
        for (Model model : models) {
            model.update(sss.getDaten());
        }
    }
}
```
Ist eigentlich ein verkapptes Observer-Muster.


----------



## bygones (25. Jan 2012)

P@u1 hat gesagt.:


> Das Model stellt ja die Anwendungsdaten und logik da.


naja - das Model ist im Grunde einfach der Datenhalter, da steckt selten Logik drinnen. Es speichert die Eigenschaften fertig aus



P@u1 hat gesagt.:


> Und der Controller ist die Strategie einer View um Benutzeraktionen zu verarbeiten.


was meistens genau die Logik ist.



P@u1 hat gesagt.:


> Wenn ich jetzt aber von außerhalb der UI ein Modell ändern will, arbeite ich dann direkt mit dem Modell oder mit einem Controller?


was ist denn ausserhalb ? Im Normalfall ist der Controller der jenige der Aenderungen ans Model schickt - aber ich versteh nicht so recht was mit du mit "ausserhalb" meinst



P@u1 hat gesagt.:


> Controller würde da ja eig nich viel Sinn machen, weil es nicht um Benutzerinteraktionen geht, sondern um Daten, die von der seriellen Schnittstelle kommen.


UI/Controller hat auch erstmal nix direkt mit Benutzereingabe zu tun.
Du hast ein Model fuer deine Daten, das haelt was weiss ich, ein paar Integers und ein paar Strings.
Dein Controller haelt das modell und bekommt Input von der Schnittstelle, verarbeitet die und sendet bei Bedarf Aenderungen ans Modell.



P@u1 hat gesagt.:


> Und wenn ich direkt mit dem Model arbeite, muss ich ja irgendwie von der Klasse, die die serielle Schnittstelle ausliest aus an die Modelle rankommen.


aka Controller



P@u1 hat gesagt.:


> Von dort aus muss ich sowohl auf das Model für die Plotdaten, als auch auf das Model für die Vitaldaten als auch auf das Model für die Sensordaten zugreifen.


d.h. in deinem Fall muss ein Controller Zugriff auf alle Models haben ?


----------

