separazione tra il presentatore (che contiene la logica) e vista (un involucro muto intorno controlli UI) consente di:
- scrivere unit test per i presentatori funzionare senza dover dell'ambiente corrispondente (desktop, browser GWT) logica
- riutilizzo front-end senza essere legati ad un particolare insieme di quadro widgets/UI
il caso d'uso quest'ultimo è raro, quindi concentriamoci sulla idoneità del modello MVP automatizzata, programmatica test. Con un team di sviluppatori questo spesso assume la forma di un ciclo di build/test continuo utilizzando Hudson (o simile) su un server headless, dove non è pratico aprire un browser Web, creare controlli, ecc. Ogni volta che viene eseguito un test.
L'utilizzo tipico di MVP + GWT è che le viste implementano un'interfaccia fornita dal presentatore e spesso questa interfaccia è definita in termini di altre interfacce generiche. Ecco un semplice presentatore che incrementa un'etichetta numerica quando un tasto è scattato - notare che, invece di esporre le TextBox e Button direttamente, la vista restituisce generici HasText e HasClickHandlers casi:
public class ButtonClickPresenter {
public interface View {
HasText currentValue();
HasClickHandlers incrementButton();
}
private final View myView;
private int currentValue = 0;
public ButtonClickPresenter(View myView) {
this.myView = myView;
this.myView.currentValue().setText("0");
this.bind(); // for the sake of demonstration
}
public void bind() {
this.myView.incrementButton.addClickHandler(
@Override
new ClickHandler() {
void onClick(ClickEvent event) {
currentValue ++;
myView.currentValue().setText(
Integer.toString(currentValue));
}
});
}
}
La vista "reale" ritorna UI widgets (creati tramite UiBinder in questo esempio):
public class ButtonClickView implements ButtonClickPresenter.View {
// ... skipped UiBinder initialisation ...
@UiField Label currentValueLabel;
@UiField Button incrementButton;
@Override
public HasText currentValue() {
return currentValueLabel;
}
@Override
public HasClickHandlers incrementButton() {
return incrementButton;
}
// ... etc ...
}
che unit test creano un'implementazione fittizio (o utilizzare Mockito, EasyMock, etc.) e pertanto non richiedono alcun componente UI:
public class ButtonClickPresenterTest {
ButtonClickPresenter presenter;
ClickHandler currentHandler;
String currentText;
@Before
public void setUp() {
presenter = new ButtonClickPresenter(
// dummy view - just stores label text in a String and
// keeps track of the Presenter's click handler
new ButtonClickPresenter.View() {
@Override
public HasText currentValue() {
return new HasText() {
@Override public String getText() { return currentText; }
@Override public void setText(String text) { currentText = text; }
};
}
@Override
public HasClickHandlers incrementButton() {
return new HasClickHandlers() {
@Override
public HandlerRegistration addClickHandler(ClickHandler handler) {
currentHandler = handler;
}
};
}
});
}
@Test
public void testIncrement() {
// initial value
assertEquals("0", currentText);
// clicking the button should increment the number
currentHandler.onClick(null);
assertEquals("1", currentText);
}
}
Per quanto riguarda il prossimo paragrafo: le vostre viste non dovrebbero assolutamente connettersi al database! Il presentatore deve richiedere i dati tramite Service/ServiceAsync (o un'astrazione come gwt-dispatch o gwt-platform), quindi chiamare i metodi sulla vista per popolare l'interfaccia utente.
Tra l'altro, questi ultimi due link (insieme con gwt-presenter) sono un buon inizio, se siete alla ricerca di esempi di codice GWT MVP - combinato con Google GIN forniscono strutture per legare tutte queste cose insieme.
Detto questo, sono d'accordo - la combinazione di GWT + MVP + Java può essere duro lavoro e estremamente verbose (Sono contento di non dover lavorare con esso molto in questi giorni). L'alternativa, tuttavia, è ancora meno attraente: una palla di spaghetti non controllabile e non gestibile ...
Fantastico !! Grazie – Barry