Secondo la descrizione di MVP di Martin Fowler ( http://martinfowler.com/eaaDev/uiArchs.html )
Della parte View di MVC, Fowler afferma:
Il primo elemento di Potel è considerare la vista come una struttura di widget, widget che corrispondono ai controlli del modello Forms and Controls e rimuovere qualsiasi separazione vista / controller. La vista di MVP è una struttura di questi widget. Non contiene alcun comportamento che descriva come i widget reagiscono all'interazione dell'utente .
(Enfasi in grassetto mia)
Quindi del presentatore:
La reazione attiva all'utente agisce in un oggetto presentatore separato. I gestori fondamentali per i gesti degli utenti esistono ancora nei widget, ma questi gestori passano semplicemente il controllo al presentatore .
Il relatore decide quindi come reagire all'evento. Potel discute questa interazione principalmente in termini di azioni sul modello, cosa che fa tramite un sistema di comandi e selezioni. Una cosa utile da evidenziare qui è l'approccio di impacchettare tutte le modifiche al modello in un comando: ciò fornisce una buona base per fornire il comportamento di annullamento / ripetizione.
(Ancora una volta, il mio enfasi è in grassetto)
Pertanto, in conformità con le linee guida di Fowler, la tua vista non dovrebbe essere responsabile di alcun comportamento in risposta all'evento pulsante; che include la creazione di un'istanza di UserInfo
. La responsabilità di decidere di creare un oggetto appartiene al metodo Presenter al quale viene inoltrato l'evento UI.
Tuttavia, si potrebbe anche sostenere che anche il gestore di eventi del pulsante della vista non dovrebbe essere responsabile del passaggio del contenuto del tuo textView
, poiché la vista dovrebbe semplicemente inoltrare l'evento del pulsante nel Presentatore e nient'altro.
Con MVP, è comune per la vista implementare un'interfaccia che il relatore può utilizzare per raccogliere i dati direttamente dalla vista (assicurando nel contempo che il presentatore sia ancora agnostico alla vista stessa). Poiché UserInfo è un semplice POJO, potrebbe essere valido per la vista esporre un getter per UserInfo che il Presentatore può prelevare dalla Vista tramite un'interfaccia.
// 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.
}
}
In che modo questo differisce dal passare UserInfo
direttamente nella vista usando il gestore eventi? La differenza principale è che il relatore è ancora alla fine responsabile della logica che causa la UserInfo
creazione di un oggetto. cioè l'evento ha raggiunto il Presentatore prima della creazione del UserInfo
, consentendo al Presentatore di prendere la decisione.
Immagina uno scenario in cui avevi la logica del presentatore in cui non volevi che UserInfo
fosse creato in base a uno stato all'interno della vista. Ad esempio, se l'utente non ha spuntato una casella di spunta sulla vista, o hai avuto un controllo di validazione su un campo da aggiungere a UserInfo che non è riuscito - il tuo presentatore potrebbe contenere un controllo aggiuntivo prima di chiamare GetUserInfo
- ad es.
private boolean IsUsernameValid() {
String username = addUserView.GetUsername();
return (username != null && !username.isEmpty());
}
public void onSomethingClicked() {
if (IsUsernameValid()) {
UserInfo userInfo = addUserView.GetUserInfo();
// etc.
}
}
Tale logica rimane all'interno del presentatore e non è necessario aggiungerla alla vista. Se la vista fosse responsabile della chiamata GetUserInfo()
, sarebbe anche responsabile di qualsiasi logica che lo circonda; che è ciò che il modello MVP sta cercando di evitare.
Quindi, mentre il metodo che crea che UserInfo
può esistere fisicamente nella classe View, non viene mai chiamato dalla classe View, solo dal Presenter.
Ovviamente, se la creazione dei UserInfo
risultati richiede controlli aggiuntivi rispetto al contenuto dei widget di input dell'utente (ad es. Conversione di stringhe, convalida, ecc.), Sarebbe meglio esporre singoli getter per quelle cose in modo che la convalida / conversione di stringhe possa richiedere posto all'interno del Presentatore - e quindi il relatore crea il tuo UserInfo
.
Nel complesso, il tuo obiettivo principale per quanto riguarda la separazione tra Presenter / View è assicurarti di non dover mai scrivere la logica nella vista. Se ti capita mai di dover aggiungere if
un'istruzione per qualsiasi motivo (anche se si tratta di if
un'istruzione relativa allo stato di una proprietà del widget - controllo di una casella di testo vuota o di un valore booleano per una casella di controllo), allora appartiene al presentatore.
onSomethingClicked()
, quindi quando l'utente fa clic su "qualcosa", il View chiamapresenter.onSomethingClicked()
? O i miei metodi presentatore dovrebbero essere nominati come le azioni previste, nel mio casoaddUser()
?