Laden...

Winforms MVP und Commandpattern: Arbeitet das Command auf den Modell oder dem Presenter?

Erstellt von serial vor 12 Jahren Letzter Beitrag vor 12 Jahren 3.502 Views
S
serial Themenstarter:in
902 Beiträge seit 2007
vor 12 Jahren
Winforms MVP und Commandpattern: Arbeitet das Command auf den Modell oder dem Presenter?

Hallo Leute,

ich stell mir gerade die Frage, wie ihr Command mit dem MVP-Muster umsetzt.
Nehmen wir an, ich habe eine einfache Orderview mit einem Orderpresenter, welche eben die Logik hält. Nun gibt es einen Button AddOrder, und eine korrespondierende Presentermethode AddOrder(). Diese fügt über einem Service der BL eine Order hinzu.

Nun möchte man aber nicht nur den Button, sondern noch einen Menüeintrag und einen Link welcher auch eine Order hinzufügt. Also könnte man ja das in ein Command kapseln und diesen verwenden. Nun die Frage: sollte der Command den entsprechenden Presenter bekommen, und dessen AddOrder()-MEthode aufrufen, oder sollte der Command direkt mit dem Model sprechen? Was ist wenn der Command ausserhalb der Ordersview verwendet wird? (Dann steht der Presenter theoretisch nicht zur Verfügung). Wie handhabt ihr das Szenario? Oder macht ihr das ganz anders?

Ich freue mich auf eure Antworten.

mfg
serial

K
62 Beiträge seit 2009
vor 12 Jahren

Die Methode AddOrder kommt ins Model und der Presenter, wie auch der Command rufen die Methode des Models auf (Der Presenter kann auf das Hinzufügen eines Orders im Model ggf. durch ein entsprechendes Event reagieren).

S
serial Themenstarter:in
902 Beiträge seit 2007
vor 12 Jahren

Hallo Kileak

Die Methode AddOrder ist narülich auch im Model, aber der Presenter hat natürlich auch eine, zum Aufruf aus der View. Also deine Meinung ist: Command arbeitet auf Model und nicht auf Presenter?

Danke

K
62 Beiträge seit 2009
vor 12 Jahren

Schon, der Presenter sollte den Aufruf einfach ans Model durchreichen.

5.742 Beiträge seit 2007
vor 12 Jahren

Command arbeitet auf Model und nicht auf Presenter?

Ich würde es so formulieren: Das Command ist Teil des Presenter bzw. auf einer Ebene mit diesem.

Ob es Zugriff auf den Presenter hat, hängt vom Anwendungsfall ab (ein "Auswahl aufheben"-Command bräuchte evtl. tatsächlich Zugriff, da die Auswahl evtl. rein UI-technisch realisiert ist).

Wie genau setzt du denn das Command-Pattern ein bzw. welchen Zweck erfolgt sein Einsatz?
Reiner Event-Ersatz zur besseren Entkopplung?
Undo-/Redo?
Commands (ähnlich wir RoutedCommands in der WPF), um gleiche Menüeinträge je nach Kontext andere Aktionen ausführen zu lassen?

In ersterem Fall würde ich dann einfach Commands mittels Delegaten im Presenter erzeugen á la:


this.AddOrderCommand = new DelegateCommand(this.CanAddOrder, this.AddOrder); //CanAddOrder und AddOrder sind (private) Methoden im Presenter

IMHO macht in diesem Szenario ein Command ohne zugehörigen Presenter keinen Sinn; letztlich ist ein Command ja nur ein Weg, eine Methode des Presenters aufzurufen (wobei sich dann natürlich die Frage stellt, wozu man das Command überhaupt braucht - ein Attribut und / oder Spezifikation der Methode wäre ja auch möglich - ähnlich wie in Caliburn für WPF)

Im letzteren Fall würde ich die Registrierung auch im Presenter abwicklen - dieser könnte dann ja auch Ziel für die Commands auftreten und würde entsprechend die richtige Aktion auswählen.

S
serial Themenstarter:in
902 Beiträge seit 2007
vor 12 Jahren

Hi winSharp93,

Undo/Redo setze ich mit dem Memento direkt im Model um, da ich mit automatischer Datenbindung arbeite.

Commands sind hier hauptsächlich da, um immer wiederkehrende Aktionen zu kapseln. Also zB AddItem-Funktion. Ich erstelle das COmmand im View und übergebe den Presenter. Danach binde ich den Command an ein Control.
Du sagst, das der Presenter die Commands erzeugen sollte? MAcht er diese dann durch Properties öffentlich verfügbar?

mfg
serial

5.742 Beiträge seit 2007
vor 12 Jahren

Du sagst, das der Presenter die Commands erzeugen sollte? MAcht er diese dann durch Properties öffentlich verfügbar?l

Wie gesagt: So pauschal kann man das nicht sagen, da es zig verschiedene Szenarien gibt, in denen man das Command-Pattern in diesem Zusammenhang einsetzen kann 😉

Commands sind hier hauptsächlich da, um immer wiederkehrende Aktionen zu kapseln. [...] Ich erstelle das COmmand im View und übergebe den Presenter.

Was steht dann in diesem Beispiel konkret in deinem View?

S
serial Themenstarter:in
902 Beiträge seit 2007
vor 12 Jahren

Hallo winSharp93,

in meinem Code steht ca soetwas:


FormLoad:

ICommand insertCommand = new InsertItemCommand(myPresenter);
CommandManager.Bind(insertCommand, insertToolStripMenuItem);
CommandManager.Bind(insertCommand, btnInsert);

mfg serial

5.742 Beiträge seit 2007
vor 12 Jahren

in meinem Code steht ca soetwas:

Ja - ich würde eher schreiben:


CommandManager.Bind(myPresenter.InsertCommand, insertToolStripMenuItem);
CommandManager.Bind(myPresenter.InsertCommand, btnInsert);
//bzw. ohne Command (Insert ist eine Methode)
CommandManager.Bind(myPresenter.Insert, insertToolStripMenuItem);

Letztlich ist ein Command bei dir - so wie ich das sehe - eh auf einen Presenter festgelegt.
Insofern sehe ich keinen Sinn, Command und Presenter nochmal auseinanderzureißen.
Das führt letztlich lediglich dazu, dass dein Presenter deutlich mehr Funktionalität öffentlich zugänglich machen muss, um vom Command verwendet werden zu können.

Da kann man den Code des Commands IMHO auch gleich in den Presenter packen.

BTW: Pass' bei deinem CommandManager auf, dass du dir kein Memory-Leak einfängst (falls er statisch ist).

S
serial Themenstarter:in
902 Beiträge seit 2007
vor 12 Jahren

Hi winSharp93,

also ja es gibt commands welche eben zB das Hinzufügen eines Items kapseln sollen.
Diese Logik ist bis jetzt im Presenter, weil er zugriff auf das model hat.
Darum ja eben die Frage, ob das COmmand den Presenter verwenden soll, oder das Model direkt!

Das ich nciht einfach ohne Commands arbeiten kann, liegt daran, das uU viele Buttons die selbe Aktion ausführen, somit ist es mit einem Command besser. Sonst müsste jeders Control immer Presenter.Methode() aufrufen.
(Oder was meinst du mit: "Da kann man den Code des Commands IMHO auch gleich in den Presenter packen.") --> kannst du das kurz demonstrieren?

NAtürlich ist es ja eigentlich so, dass ein View einen Presenter hat, und ein Model, sodass ein anderes View normlerweise NICHT Aktionen aus einem anderen View aufruft. Aber ich habe eine Art "Schnellaktionen", welche eben Aktionen aus unterschiedlichen Views bereitstellt. Da dachte ich mir kommen Commands ganz gut.

mfg
serial

5.742 Beiträge seit 2007
vor 12 Jahren

Darum ja eben die Frage, ob das COmmand den Presenter verwenden soll, oder das Model direkt!

Meiens Erachtens eher das Modell, sonst müsstest du ja lauter Methoden im Presenter hinzufügen, die nur die Model-Methoden aufrufen:


//Presenter:
public void AddItem()
{
   model.Items.Add(new Item());
}

//Command:
public void Execute()
{
   presenter.AddItem();
}

(Oder was meinst du mit: "Da kann man den Code des Commands IMHO auch gleich in den Presenter packen.") --> kannst du das kurz demonstrieren?

Statt des Codes oben kann man das Command dann IMHO auch gleich weglassen:


//Presenter:
//Wird vom View aufgerufen
public void AddItem()
{
   model.Items.Add(new Item());
}

Sonst müsste jeders Control immer Presenter.Methode() aufrufen.

Wie gesagt: Da reicht ein Delegate und eine Methodensignatur in deinem CommandManager:


void Bind(Action action, Button button);
//Aufruf:
CommandManager.Bind(() => presenter.AddItem(), myButton);