MVC - Funktionsweise des Controllers

Status
Nicht offen für weitere Antworten.

Marcel_Handball

Bekanntes Mitglied
Hi,

ich habe noch eine letzte Frage zum MVC-Pattern.

Wird in der View ein Button betätigt, wird der entsprechende Actionlistener in der View aufgerufen. Soll dieser nun eine bestimmte Methode des Controllers aufrufen?
Oder sollte sich der Controller bei allen relevanten Views als Listner anmelden, sodass der Button in der View ein Ereignis auslöst?

Und wenn beim Drücken auf den Button der Wert eines Textfeldes (oder mehrere Eingaben des Users) dem Controller bekannt gegeben werden soll, sollte der Controller eine Referenz auf die Views haben oder sollten die Werte übergeben werden?



Einfach gefragt: Wie genau sieht das Wechselspiel/Austausch zwischen View und Controller aus?
 
Zuletzt bearbeitet:

Marco13

Top Contributor
Wieder nur ein Link auf eine Diskussion, in der ich schonmal was dazu gesagt hatte, als jemand über ein http://www.java-forum.org/allgemein...ein-software-pattern-beispiel.html#post501747 reden wollte.

Oder um es mit dem dort geposteten Link zu beantworten:
What's a Controller, Anyway?
An accountant who gets promoted?

Zusammengefasst finde ich, dass man (bei "normalen", nicht-webbasierten) Anwendungen nicht einen dicken, großen, one-rules-all-Controller hat, sondern dass eben jeder (auch anonyme) Listener, der an irgendeinen Button gehängt wird, ein kleiner Controller ist.

So eine "Umleitung"
Java:
class View
{
    private Model model;
    private Controller controller;

    void init()
    {
        someButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                controller.changeSomething();
            }
        });
    }
}

class Controller
{
    private Model model;

    void changeSomething()
    {
        model.changeSomething();
    }
}

macht IMHO wirklich keinen Sinn, weil man auch einfach
Java:
            public void actionPerformed(ActionEvent e)
            {
                model.changeSomething();
            }
schreiben und den Controller als solchen weglassen könnte.


Die Alternativen im Stile von
Java:
class Controller implements ActionListener // und viele andere
{
    void init()
    {
        ...
        view.addActionListenerToButton(this);
    }

    public void actionPerformed(ActionEvent e)
    {
        if (e.getActionCommand().equals("changeSomething"))
        {
            model.changeSomething();
        }
    }
}
oder
Java:
class Controller
{
    private ActionListener buttonActionListener = new ActionListener()
    {
        public void actionPerformed(ActionEvent e)
        {
            model.changeSomething();
        }
    });

    void init()
    {
        ...
        view.addActionListenerToButton(buttonActionListener);

        // Oder sogar
        view.getThisSpecialButton().addActionListener(buttonActionListener);
    }

}
oder die "Mischformen", die man sich da ausdenken könnte, bringen IMHO auch keine Vorteile, sondern nur Nachteile im Sinne von mehr Schreibaufwand und geringerer Flexibilität.

Bin aber für Gegenargumente offen...
 

Marcel_Handball

Bekanntes Mitglied
Wann ist das Nutzen eines "externen" Controllers denn dann sinnvoll?

Edit:

Würde in der View der Aufruf von model.changeSomething(); geschehen, folgt daraus ja, dass die Funktionsweise des Programms im Model steckt. Dieses soll aber doch mit dem Programmablauf kaum zu tun haben, sondern lediglich die Daten verwalten.

Das wäre aus meiner Sicht ein Grund, den Code in einen Controller zu packen, um dort die Funktionsweise des Programmes zu implementieren.
Somit scheint mir der direkte Aufruf der Model-Methoden, beim Ändern einzelner Werte sinnvoll und bei umfangreicheren Aktionen (Verbindung zu Datenbank,...) einen Aufruf des Controllers.

Aber welches wäre die sinnvollere Lösung zum Verbindung von View und Controller, über Methodenaufrufe oder auch über Listener?
 
Zuletzt bearbeitet:

Atze

Top Contributor
die listener sind doch schon die controller in dem fall, oder? weil die haben weder viel mit der view, noch mit dem model zu tun. sie gehören doch zur logik, oder seh ich das falsch?
 

ARadauer

Top Contributor
ich bin ganz marcos Meinung.. ich hab mir nach einiger Zeit auch angewöhnt den Controller weg zu lassen, da er oft nur weiterleitet... irgendjemand hat mir mal gesagt, dass man das Model-Presenter Pattern nennt....
 

Marco13

Top Contributor
Wie in dem verklinkten Thread steht (ja, sorry, der ist ziemlich lang, muss man sich nicht alles durchlesen) ist ein eigener Controller ggf. bei Anwendungen notwendig, wo (sinngemäß) Model und View über's Netzwerk kommunizieren sollen.

Der Einwand, dass bei dem skizzierten Vorgehen die Funktionalität im Modell stecken würde, ist (als Einwand) berechtigt - genauer: Das sieht im Moment so aus, als würde die gesamte Funktionalität im Modell stecken. Das Modell an sich bietet ja auch Methoden an, die etwas "machen", d.h. es ist nicht notwendigerweise nur reine Datenhaltung, sondern die Modellierung eines Objektes, das bestimmte Funktionalitäten hat.

Eine klassische "Rechtfertigung" für den Controller ist manchmal, dass er ggf. Benutzereingaben auf Gültigkeit überprüft, bevor er sie ans Modell weiterreicht. Man könnte jetzt zwar sagen: "Wenn der Benutzer etwas machen kann, was er nicht darf, ist die View falsch entworfen", aber so pauschal funktioniert das natürlich nicht.

Aber wie gesagt: Jeder kleine, anonyme Listener ist (nach meiner, höchst subjektiven Interpretation) ein kleiner Controller. D.h. in der actionPerformed muss ja nicht notwendigerweise EINE Anweisung wie [c]model.doSomething[/c] stehen, die eine komplexe Funktionaität abbildet, die das Modell in seiner eigentlichen Fassung gar nicht anbieten wollte oder sollte - stattessen kann dort ja auch stehen
Code:
public void actionPerformed(ActionEvent e)
{
    String input = getUserInput();
    if (isValid(input))
    {
        model.setValue(input);
        model.changeSomething();
    }
    model.doSomethingElse();
}
also irgendeine Folge von Aweisungen, die diser kleine Controller eben ausführen soll.

Natürlich sollte so eine "actionPerformed" Methode in einer anonymen Klasse nicht zu lang werden. Ich würde das ganze dann ggf. in ein private Methode der View packen - und es KANN auch sinnvoll sein, mehrere solcher Funktionen dann in einer Klasse zusammenzufassen, die man "Controller" nennt....

Nur damit das nicht falsch ankommt: Ich wollte nicht sagen, dass es nie einen Controller verwenden sollte, sondern nur, dass man nicht pauschal JEDE Funktionalität (die ggf. eben doch mit einem [c]model.doSomething[/c] ausführen könnte) "von Hinten durch die Brust ins Auge" (oder eben von hinten durch den Controller ins Modell) schleusen sollte. Einen Controller zu erstellen, der nur Arbeit macht und unflexibler ist, nur weil da eben dieses "C" in "MVC" steht, wäre ja unzweckmäßig.
 

Marcel_Handball

Bekanntes Mitglied
@ARadauer: also rufst du die Model-Methoden direkt aus der View auf?

Aber deine Views sind weiterhin beim Model angemeldet, oder?
Theoretisch könnte die View sich dann auch gleich selbst aktualisieren (sofern es nicht mehrere Views gibt, die das gleiche Model nutzten)
 
Zuletzt bearbeitet:

Marco13

Top Contributor
Hmja, könnte sie in manchen Fällen vielleicht... wenn man sich den einfachsten Fall vorstellt
Code:
class View implements ModelListener
{
    private Model model;

    void actionPerformed()
    {
        model.setValue("12345");
    }

    // Listener-Methode, die indirekt von "model.setValue" ausgelöst wird
    void modelChanged(ModelChangedEvent e) 
    {
        someTextField.setText(model.getValue()); // Schreibt "12345" ins TextField
    }
}
dann KÖNNTE man natürlich auch direkt das, was der "modelChanged"-Methode steht, in die actionPerformed schreiben:
Code:
    void actionPerformed()
    {
        model.setValue("12345");
        someTextField.setText("12345"); // Schreibt AUCH "12345" ins TextField
    }
aber das ist "gefährlich": Erstens macht man damit ziemlich viele Annahmen über das Verhalten des Modells, zweitens kann man sich leicht Inkonsistenzen einhandeln, wenn man versehentlich ein falsche Änderung macht, und nicht zuletzt ist es potentiell unnötiger Aufwand: Warum sollte man
Code:
    void actionPerformed()
    {
        model.setValue("12345");
        someTextField.setText("12345"); 
        someTextField0.setText("1"); 
        someTextField1.setText("2"); 
        someTextField2.setText("3"); 
        // Noch 10 andere Sachen...
    }

    void modelChanged(ModelChangedEvent e) 
    {
        someTextField.setText(model.getValue()); // Schreibt "12345" ins TextField
        someTextField0.setText("1"); 
        someTextField1.setText("2"); 
        someTextField2.setText("3"); 
        // Noch 10 andere Sachen...
    }
doppelt hinschreiben, wenn man das ganze in der actionPerformed-Methode einfach weglassen könnte? (In der modelChanged-Methode braucht man es ja auf jeden Fall, weil man nie wissen kann, ob diese View die einzige ist, die ggf. auf dem Modell "setValue" aufruft....)
 

Marcel_Handball

Bekanntes Mitglied
Alles klar, erstmal vielen Danke für die ausführlichen Erklärungen.

Werde im Laufe des Tages auch mal den Thread "Einfaches MVC-Beispiel" durchlesen und dann anfangen mein MVC-Grundgerüst aufbauen.
 

muckelzwerg

Bekanntes Mitglied
Eines der wichtigsten Ziele bei diesem und anderen Pattern ist die Austauschbarkeit.
Wenn Du verschiedene, vom Aufgabenbereich zusammenhängende Objekte hast, willst Du die unter Umständen
mal gegen eine andere Variante (anderer View) etc. austauschen.
Wenn die Trennung zwischen diesen "Bereichen" und den zugehörigen Objekten nicht wirklich vorhanden ist
("Wer ruft wen auf?", Message-Passing vs "SharedMemory/SharedObjects" vs Funktionsaufruf ...),
dann wird es dabei meist Probleme geben. Was Du dann "Controller" nennst und was nicht, ist dann ziemlich egal,
die Namen nützen dann nichts mehr.
Bei MVC trennt man zwischen Darstellung, Halten der Daten und zugehöriger Algorithmen (suchen, sortieren, etc.) und dem Ausführen der eigentlichen Aufgaben.
Bei vielen Projekten kann es passieren, dass in der "Datenverarbeitung" bereits fast das ganze Projekt drinsteckt und man eigentlich eine Art "Datenspeicher mit Frontend" gebaut hat. Da wird ein expliziter Controller eher umständlich werden und vielleicht sogar Schwierigkeiten machen.
Du kannst Dein Projekt ja mal abklopfen auf die Frage "Kann ich meinen View, durch eine Konsole, die Grafikoberfläche eines Videospiels oder sonstwas ersetzen". "Kann ich meine Datenbank, durch ein System mit Flatfiles, oder einen Webservice oder ... ersetzen". "Kann ich die Logik meines Programmes durch die (schlaueren) Routinen eines anderen Entwickler ersetzen, ohne jede Funktion von Hand zu übetragen?".
Desingpattern sind eigentlich für das koordinierte Verteilen von Aufgabenbereichen zuständig und nützen viel bei der Modularisierung. Aber man sollte eben unbedingt mal schauen, welche Aufgaben man überhaupt hat.

-- -- muckelzwerg
 
J

JohannisderKaeufer

Gast
Was mich persönlich vom weglassen des Controllers abhält ist die Tatsache das es ungemein schwieriger wird automatisiert zu testen.

Wenn ich eine Model - ViewController Architektur habe, muß ich eventuell eine komplette Swinganwendung testen. Damit meine ich Knöpfchen Drücken, Rückgabewerte überprüfen, etc. und das automtisch ablaufen lassen finde ich ungemein schwieriger und aufwendiger als folgendes:

Habe ich aber einen eigenständigen Controller, so kann ich einen JUnit-Test schreiben der einen Methode des Controllers aufruft. Die korrekte Änderung des Models kann ich am Model überprüfen.
Wird die View über das Observerpattern benachrichtigt, kann ich hier einen Mock schreiben um die Updates im Unittest zu überprüfen.

Klar muß ich irgendwann auch mal die gesamte Anwendung testen, bzw. die View, wenn ich aber schon Model und Controller exzessiv getestet habe, werde ich damit weit weniger Probleme bekommen.
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen

Neue Themen


Oben