Laut Martin Fowlers Beschreibung von MVP ( http://martinfowler.com/eaaDev/uiArchs.html )
Über den View-Teil von MVC sagt Fowler:
Das erste Element von Potel besteht darin, die Ansicht als eine Struktur von Widgets zu behandeln, Widgets, die den Steuerelementen des Formular- und Steuerelementmodells entsprechen, und jegliche Trennung von Ansicht und Controller zu entfernen. Die Ansicht von MVP ist eine Struktur dieser Widgets. Es enthält kein Verhalten, das beschreibt, wie die Widgets auf Benutzerinteraktionen reagieren .
(Fettgedruckte Betonung meiner)
Dann vom Moderator:
Die aktive Reaktion auf Benutzerhandlungen lebt in einem separaten Präsentatorobjekt. Die grundlegenden Handler für Benutzergesten sind in den Widgets noch vorhanden, diese Handler geben jedoch lediglich die Kontrolle an den Präsentator weiter .
Der Moderator entscheidet dann, wie er auf das Ereignis reagieren soll. Potel diskutiert diese Interaktion hauptsächlich im Hinblick auf Aktionen am Modell, die durch ein System von Befehlen und Auswahlen ausgeführt werden. Hervorzuheben ist hier der Ansatz, alle Änderungen am Modell in einem Befehl zu verpacken. Dies bietet eine gute Grundlage für das Bereitstellen von Rückgängig- / Wiederherstellungsverhalten.
(Wieder kühne Betonung meiner)
In Übereinstimmung mit den Fowler-Richtlinien sollte Ihre Ansicht daher nicht für ein Verhalten als Reaktion auf das Schaltflächenereignis verantwortlich sein. Dazu gehört das Erstellen einer Instanz von UserInfo
. Die Verantwortung für die Entscheidung, ein Objekt zu erstellen, liegt bei der Presenter-Methode, an die das UI-Ereignis weitergeleitet wird.
Man könnte jedoch auch argumentieren, dass der Schaltflächenereignishandler der Ansicht auch nicht für die Übergabe des Inhalts von Ihnen verantwortlich textView
sein sollte, da die Ansicht lediglich das Schaltflächenereignis an den Präsentator weiterleiten sollte und nicht mehr.
Bei MVP ist es üblich, dass die Ansicht eine Schnittstelle implementiert, über die der Präsentator Daten direkt aus der Ansicht abrufen kann (wobei sichergestellt wird, dass der Präsentator immer noch unabhängig von der Ansicht selbst ist). Da UserInfo ein einfaches POJO ist, kann es für die Ansicht gültig sein, einen Getter für UserInfo bereitzustellen, den der Präsentator über eine Schnittstelle aus der Ansicht abrufen kann.
// The view would implement IView
public interface IView {
public UserInfo GetUserInfo();
}
// Presenter
public class AddUserPresenter {
private IView addUserView;
public void SetView(IView view) {
addUserView = view
}
public void onSomethingClicked() {
UserInfo userInfo = addUserView.GetUserInfo();
// etc.
}
}
Wie unterscheidet sich dies von der UserInfo
direkten Übergabe des Ereignisses mit dem Ereignishandler an die Ansicht? Der Hauptunterschied besteht darin, dass der Präsentator letztendlich immer noch für die Logik verantwortlich ist, durch die ein UserInfo
Objekt erstellt wird. dh das Ereignis erreichte den Präsentator vor der Erstellung des UserInfo
, sodass der Präsentator die Entscheidung treffen konnte.
Stellen Sie sich ein Szenario vor, in dem Sie eine Präsentatorlogik hatten, in der Sie nicht wollten, dass UserInfo
diese basierend auf einem bestimmten Status in der Ansicht erstellt wird. Zum Beispiel hat , wenn der Benutzer nicht eine Checkbox auf der Ansicht aktiviert, oder Sie haben eine Plausibilitätsprüfung gegen einig Feld in Userinfo hinzugefügt werden , die fehlgeschlagen - Ihr Moderator ist eine zusätzliche Kontrolle enthalten könnte vor dem Aufruf GetUserInfo
- dh
private boolean IsUsernameValid() {
String username = addUserView.GetUsername();
return (username != null && !username.isEmpty());
}
public void onSomethingClicked() {
if (IsUsernameValid()) {
UserInfo userInfo = addUserView.GetUserInfo();
// etc.
}
}
Diese Logik verbleibt im Präsentator und muss nicht zur Ansicht hinzugefügt werden. Wenn die Ansicht für das Aufrufen verantwortlich GetUserInfo()
wäre, wäre sie auch für jede Logik verantwortlich, die ihre Verwendung umgibt. Das ist es, was das MVP-Muster zu vermeiden versucht.
Während die Methode, die das erstellt, UserInfo
möglicherweise physisch in der View-Klasse vorhanden ist, wird sie niemals von der View-Klasse aufgerufen, sondern nur vom Presenter.
Wenn die Erstellung der UserInfo
Widgets zusätzliche Überprüfungen des Inhalts von Benutzereingabe-Widgets erfordert (z. B. Zeichenfolgenkonvertierung, Validierung usw.), ist es natürlich besser, einzelne Getter für diese Dinge verfügbar zu machen, damit die Validierung / Zeichenfolgenkonvertierung durchgeführt werden kann Platzieren Sie innerhalb des Präsentators - und dann erstellt der Präsentator Ihre UserInfo
.
Insgesamt besteht Ihr Hauptziel in Bezug auf die Trennung zwischen Präsentator und Ansicht darin, sicherzustellen, dass Sie niemals Logik in die Ansicht schreiben müssen. Wenn Sie if
aus irgendeinem Grund jemals eine Anweisung hinzufügen müssen (auch wenn es sich um eine if
Anweisung zum Status einer Widget-Eigenschaft handelt - Aktivieren eines leeren Textfelds oder eines Booleschen Werts für ein Kontrollkästchen), gehört diese in den Präsentator.
onSomethingClicked()
so zu benennen: Wenn der Benutzer auf "etwas" klickt, ruft die Ansicht aufpresenter.onSomethingClicked()
? Oder sollten meine Präsentationsmethoden in meinem Fall als die beabsichtigten Aktionen benannt werdenaddUser()
?Presenter
ist natürlich eher für die UI-Logik als für die Domänenlogik verantwortlich und speziell auf dieView
Konzepte zugeschnitten . Daher sollten Konzepte, die existieren sollten, UI-Konzepte sein. Daher ist eine benannte Methode in deronSomethingClicked()
Tat angemessen. Im Nachhinein riecht die Benennung, die ich in meinem obigen Beispiel gewählt habe, nicht ganz richtig :-).GetUserInfo
Methode in der von Ihnen erwähnten Ansicht zu haben (wird vom Moderator ausgelöst). Was ist mit den möglichenif
Bedingungen innerhalb derGetUserInfo
Methode? Vielleicht werden einige Felder von UserInfo über die Benutzerreaktion festgelegt? Ein Szenario: Möglicherweise aktiviert der Benutzer ein Kontrollkästchen, dann sind einige neue Komponenten (möglicherweise ein neuer EditText) für den Benutzer sichtbar. In diesem Fall hat dieGetUserInfo
Methode eine if-Bedingung. In diesem SzenarioGetUserInfo
ist noch gültig?UserInfo
als Modell der Ansicht (auch als " Ansichtsmodell " bezeichnet) - In diesem Szenario würde ich denboolean
Status des Kontrollkästchens und den leeren / nullbarenString
Status des Textfelds hinzufügenUserInfo
. Sie könnten sogar in Betracht ziehen, es umzubenennen,UserInfoViewModel
wenn dies dazu beiträgt, dass das POJO eine Klasse ist, deren einziger wirklicher Zweck darin bestehtUserInfoPresenter
, Informationen über den Ansichtsstatus herauszufinden.