MVC Umsetzung

d3rbastl3r

Bekanntes Mitglied
Hallo,

ich bin irgendwie bisher gescheitert eine vernunftige lösung zu finden wie ich die View und den Controller sinnvoll verbinden kann.

Struktur: Controller ist die Oberklasse die die Model und View Objekte enthält und steuert.

Problem:
Ich habe einen Formular, dieser wird von einem Benutzer gefüllt und abgesendet, nun soll das versenden der Daten der Controller übernehmen. Bislang habe ich das so gelöst dass die View den Controller übergeben bekommen hat, so konnte ich bei einem Event (der in der View ausgelöst wurde) funktionen der Controller ansteuern.

Hat da jemand einen anderen Lösungsansatz?
 

nicco80

Mitglied
Hi,
ich denke du solltest darauf achten model, view und controller auch wirklich voneinander zu trennen.
Der View den Controller zu übergeben ist nicht korrekt.
Da du schreibst, das der Controller ein Form abschickt, vermute ich dass es ein web-form ist?

Unter Umständen könnte es sein, dass das Model-View-Presenter Pattern auf deinen Anwendungsfall besser passt; Schau mal in Wikipedia: Model View Presenter ? Wikipedia

Beschreib mal ein wenig was genau gemacht werden soll, und wie es bisher aussieht vielleicht sieht jemand 'aus der Ferne' leichter wo der Design Fehler steckt :)
 

d3rbastl3r

Bekanntes Mitglied
ich denke du solltest darauf achten model, view und controller auch wirklich voneinander zu trennen.
Der View den Controller zu übergeben ist nicht korrekt.
Mir war bekannt dass das nicht Korrekt sein kann, aber ich wusste einfach nicht wie ich das sonst lösen soll

Da du schreibst, das der Controller ein Form abschickt, vermute ich dass es ein web-form ist?
Nein, das Beispiel mit Formular war wirklich nur ein beispiel, viel mehr bezog sich das auf die events die von der View ausgelöst werden. Die Funktionen die von den Events ausgelöst werden befinden sich ja in der View, ich möchte aber aus der view direkt die funktionen des controllers aufrufen falls ein event ausgelöst wird.

Beschreib mal ein wenig was genau gemacht werden soll, und wie es bisher aussieht vielleicht sieht jemand 'aus der Ferne' leichter wo der Design Fehler steckt :)
Weis garnicht wie ich auf die Frage antworten soll xD
Das problem bezieht sich nicht auf einen bestimmten Projekt und nicht nur auf Java.
Ich habe einfach keine Idee wie ich Events der View und den Controller sinvoll und sauber verbinden kann.

Habe mir eben den WikiArtikel durchgelesen. Das ist genau das Model was ich umzusetzen versuche.
Mir ist trotzdem unklar wie die View im falle eines events den Controller / Presenter anstossen soll wenn diese ihn nicht kennt bzw. keinen Zugriff auf die functionen hat.
 
Zuletzt bearbeitet:

nicco80

Mitglied
Weis garnicht wie ich auf die Frage antworten soll xD
Das problem bezieht sich nicht auf einen bestimmten Projekt und nicht nur auf Java.
Ich habe einfach keine Idee wie ich Events der View und den Controller sinvoll und sauber verbinden kann.

Habe mir eben den WikiArtikel durchgelesen. Das ist genau das Model was ich umzusetzen versuche.
Mir ist trotzdem unklar wie die View im falle eines events den Controller / Presenter anstossen soll wenn diese ihn nicht kennt bzw. keinen Zugriff auf die functionen hat.

Vergegenwärtige dir mal, dass der Controller der Benutzer ist, denn wenn DER einen Button klickt, kontrolliert er das modell.
D.h. am Beispiel eines Buttons wird actionPerformed aufgerufen, im code davon rufst du dann am besten nur einen einzeiler auf um im gui code keine logik unterzubringen.
Wenn das Modell ein Textdokument ist und der Button die markierte Schrift fett machen soll, könnte das so gehen:
Java:
public void actionperformed(ActionEvent e) {
Application.getCurrentDocument().changeSelectedText(Text.BOLD);
}
hier kennt die view den controller nicht... um es mit deinen worten zu beschreiben. ABER es löst im modell durch die Änderung ein model-changed Ereignis aus, das die View wiederum benachrichtigen kann neu zu zeichnen - in paintComponent(Graphics g) würde dann die entsprechende Textpassage fett gedruckt, diese wird aufgerufen, weil zb. Application.getCurrentDocument().registerModelListener(this);
dafür sorgt, dass die View bei Änderung des Modells auch benachrichtigt wird.
 

d3rbastl3r

Bekanntes Mitglied
Verstehe das ganze irgendwie trotzdem noch nicht ganz *kopfkratz*

Mal vielleicht doch ein konkreteres beispiel:
Wir haben 3 Klassen, nennen wir diese Model, View und Controller

Model:
Java:
public class Model{
    protected int zaehler;

    public void Model(){
        this.zaehler = 0;
    }

    /**
     * Erhöht den Zähler um eins
     */
    public incZaehler(){
        this.zaehler++;
    }
}

Controller:
Java:
public class Controller{
    protected Model model;
    protected View view;
    
    public void Controller(){
        this.model = new Model();
        this.view = new View();
    }

    public void inc(){
        this.model.incZaehler();
    }
}

View: Die View enthält einen Button mit seiner ActionPerformed funktion
Wird nun das button geklickt so soll der zähler der model hochgezählt werden, also muss die funktion "inc" in dem controller aufgeruffen werden.
 

Marco13

Top Contributor
Die Frage taucht immer wieder auf. Und jedes erneute Auftauchen und die daraus resultierenden Diskussionen sind für mich persönlich eine Bestätigung dessen, was ich in http://www.java-forum.org/allgemeine-java-themen/80980-ganz-einfaches-mvc-beispiel.html#post501747 und http://www.java-forum.org/allgemeine-java-themen/87281-mvc-funktionsweise-controllers.html#post549888 und geschrieben hatte. Insbesondere das zweite ist ein Beispiel das ganz gut zu deinem Code passt, und zeigt, welche Möglichkeiten du jetzt hättest, das umzusetzen. Kannst ja mal schauen welche davon dir am sinnvollsten erscheint....
 

d3rbastl3r

Bekanntes Mitglied
Ah, ok, vielen dank.

Also als ich deinen zweiten link angeschaut hatte @Marco13, ist mir da eine Idee gekommen.
Wieso Eventlistener in der View, kann mir auch von der View den Button zurückgeben lassen und dann im Controller den Eventlistener setzen, also quasi in der art
this.view.getButtonX().addActionListener()...

malschauen obs so umsetzbar ist.
 

Marco13

Top Contributor
Ja, aber wie dort auch schon stand: Das hat unter Umständen(!) nur Neichteile, im Sinne von höherem Schreibaufwand (ohne daraus resultierende Vorteile) und geringerer Flexibilität. In diesem Fall müßte die View ja ALLE ihre Elemente nach draußen sichtbar machen. In diesem Fall hätte sie die Methode [c]getButtonX()[/c]. Man könnte dann erstens nicht verhindern, dass jemand von außen sowas macht wie
Code:
view.getButtonX().setText("Ätsch");
view.getButtonX().setEnabled(false);
und zweitens wäre man damit immer auf einen JButton festgelegt. Es wirkt im ersten Moment konstruiert, aber verdeutlicht vielleicht das ""Problem"" (wenn man es so nennen will) : Wenn man in der View nun statt dieses JButtons eine JCheckBox verwenden wollte, müßte u.U. der Code an mehreren Stellen geändert werden (die Schnittstelle der View (im Sinne der von ihr angebotenen Methoden) würde sich ändern). Weniger konstruiert wirkt dieser Fall vielleicht bei funktional "ähnlichen" Elementen: Es ist nicht ungewöhnlich, dass man z.B. eine JCheckBox durch einen JToggleButton oder vielleicht einen JRadioButton ersetzen will...
 

d3rbastl3r

Bekanntes Mitglied
Wollte jetzt keinen weiteren thread öffnen weils eigentlich um dasselbe thema geht.

Könnte mir jemand den sinn folgender zeilen in einer View erklären?
Java:
java.awt.EventQueue.invokeLater(new Runnable() {
    public void run() {
        new View().setVisible(true);
    }
});

Könnte doch auch statdesse auch folgendes schreiben
Java:
View view = new View();
this.view.setVisible(true);

View() ist hier eine JFrame-Klasse.

Mir ist klar dass im ersten abschnitt die Oberfläche in einem eigenem Thread gestartet wird ... doch welche vorteile habe ich jetzt davon?

Hintergrund: Wegen dem ersten codeabschnitt habe ich probleme die eventlistener der buttons im controller zu erzeugen weil dann meine view im controller nix mehr mit der view zutun hat die dann im thread läuft.
 

Marco13

Top Contributor
Swing-Components müssen auf dem Event-Dispatch-Thread erzeugt werden (und alle Änderungen an Swing-Components müssen auch vom EDT gemacht werden).

Du kannst die View vielleicht so erstellen
Code:
class X
{
    private View view = null;

    void init()
    {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                view = new View();
                view.setVisible(true);
            }
        });
        view.machWas();
    }
}
(da müssen dann noch ein paar try/catch drumrum...)
 

d3rbastl3r

Bekanntes Mitglied
Ja, aber wie dort auch schon stand: Das hat unter Umständen(!) nur Neichteile, im Sinne von höherem Schreibaufwand (ohne daraus resultierende Vorteile) und geringerer Flexibilität. In diesem Fall müßte die View ja ALLE ihre Elemente nach draußen sichtbar machen. In diesem Fall hätte sie die Methode [c]getButtonX()[/c]. Man könnte dann erstens nicht verhindern, dass jemand von außen sowas macht wie
Code:
view.getButtonX().setText("Ätsch");
view.getButtonX().setEnabled(false);
und zweitens wäre man damit immer auf einen JButton festgelegt. Es wirkt im ersten Moment konstruiert, aber verdeutlicht vielleicht das ""Problem"" (wenn man es so nennen will) : Wenn man in der View nun statt dieses JButtons eine JCheckBox verwenden wollte, müßte u.U. der Code an mehreren Stellen geändert werden (die Schnittstelle der View (im Sinne der von ihr angebotenen Methoden) würde sich ändern). Weniger konstruiert wirkt dieser Fall vielleicht bei funktional "ähnlichen" Elementen: Es ist nicht ungewöhnlich, dass man z.B. eine JCheckBox durch einen JToggleButton oder vielleicht einen JRadioButton ersetzen will...
Stimmt, hast recht.

Swing-Components müssen auf dem Event-Dispatch-Thread erzeugt werden (und alle Änderungen an Swing-Components müssen auch vom EDT gemacht werden).

Du kannst die View vielleicht so erstellen
Code:
class X
{
    private View view = null;

    void init()
    {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                view = new View();
                view.setVisible(true);
            }
        });
        view.machWas();
    }
}
(da müssen dann noch ein paar try/catch drumrum...)
view.machWas(); funktioniert so nicht *kopfkratz*
EDIT: ahh, funktioniert doch, aber nur bei invokeAndWait nciht bei invokeLater.
 
Zuletzt bearbeitet:

Ähnliche Java Themen

Neue Themen


Oben