Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Separation between the presenter (which contains logic) and view (a dumb wrapper around UI controls) allows you to:</p> <ul> <li>write unit tests for the presenters that can run without needing the corresponding environment (desktop, browser, GWT widgets)</li> <li>reuse front-end logic without being tied to a particular set of widgets/UI framework</li> </ul> <p>The latter use case is rare, so let's focus on the MVP model's suitability for automated, programmatic testing. With a team of developers this often takes the form of a continuous build/test cycle using <a href="http://hudson-ci.org/" rel="noreferrer">Hudson</a> (or similar) on a headless server, where it's not practical to open a web browser, create controls, etc. every time a test is run.</p> <p>Typical usage of MVP+GWT is that views implement an interface provided by the presenter, and often this interface is defined in terms of other generic interfaces. Here's a very simple presenter that increments a numeric label when a button is clicked - note that instead of exposing the <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/ui/TextBox.html" rel="noreferrer">TextBox</a> and <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/ui/Button.html" rel="noreferrer">Button</a> directly, the view returns generic <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/ui/HasText.html" rel="noreferrer">HasText</a> and <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/event/dom/client/HasClickHandlers.html" rel="noreferrer">HasClickHandlers</a> instances:</p> <pre><code>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)); } }); } } </code></pre> <p>The "real" view returns UI widgets (created via UiBinder in this example):</p> <pre><code>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 ... } </code></pre> <p>whereas unit tests create a dummy implementation (or use <a href="http://code.google.com/p/mockito/" rel="noreferrer">Mockito</a>, <a href="http://easymock.org/" rel="noreferrer">EasyMock</a>, etc.) and thus don't require any UI components:</p> <pre><code>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); } } </code></pre> <p>As for your next paragraph: your views shouldn't be connecting to the database at all! The presenter should request data via Service/ServiceAsync (or an abstraction such as <a href="http://code.google.com/p/gwt-dispatch/" rel="noreferrer">gwt-dispatch</a> or <a href="http://code.google.com/p/gwt-platform/" rel="noreferrer">gwt-platform</a>), then call methods on the view to populate the UI.</p> <p>By the way, those last two links (along with <a href="http://code.google.com/p/gwt-presenter/" rel="noreferrer">gwt-presenter</a>) are a good start if you're looking for GWT MVP code samples - combined with <a href="http://code.google.com/p/google-gin/" rel="noreferrer">Google GIN</a> they provide frameworks for tying all this stuff together.</p> <p>Having said all that, I agree - the combination of GWT+MVP+Java can be hard work and <strong>extremely</strong> verbose (I'm glad I don't have to work with it much these days). The alternative, though, is even less attractive: an untestable, unmaintainable ball of spaghetti...</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload