Chris Ramsdale, Google Developer Relations
Updated March 2010
Also see Part II of this article.
Building any large scale application has its hurdles, and GWT apps are no exception. Multiple developers working simultaneously on the same code base, while maintaining legacy features and functionality, can quickly turn into messy code. To help sort things out we introduce design patterns to create compartmentalized areas of responsibility within our project.
There are various design patterns to choose from; Presentation-abstraction-control, Model-view-controller, Model-view-presenter, etc... And while each pattern has its benefits, we have found that a Model-view-presenter (MVP) architecture works best when developing GWT apps for two main reasons. First the MVP model, much like other design patterns, decouples development in a way that allows multiple developers to work simultaneously. Secondly, this model allows us to minimize our use of GWTTestCase and, for the bulk of our code, write lightweight (and fast) JRE tests.
At the heart of this pattern is the separation of functionality into components that logically make sense, but in the case of GWT there is a clear focus on making the view as simple as possible in order to minimize our reliance on GWTTestCase and reduce the overall time spent running tests.
Building an MVP based application can be straightforward and easy once you understand the fundamentals behind this design pattern. To help explain these concepts we will use a simple Contacts application as an example. This application will allow users to view, edit, and add contacts to a list of contacts that are stored on the server.
To begin we will break our application up into the following components:
We'll then look into how each of these components interact by digging into:
The sample project, referenced throughout this tutorial, can be found here.
A model encompasses business objects, and in the case of our Contacts application we have:
- Contact: A representation of a contact within the contact list. For simplicity, this object contains a first name, last name, and email address. In a more complex application, this object would have more fields.
- ContactDetails: A light version of the Contact that contains only the unique identifier and display name. This "light" version of the Contact object will make the Contact list retrieval more efficient, as there will be fewer bits to serialize and transport across the wire. In the case of our example application, this optimization has less impact than it would in a more complex app where Contact objects have substantially more fields. The initial RPC will return a list of ContactDetails, and we've added a display name field so that there is some amount of data that can be displayed (within the ContactsView) without having to making subsequent RPCs.
A view contains all of the UI components that make up our application. This includes any tables, labels, buttons, textboxes, etc... Views are responsible for the layout of the UI components and have no notion of the model. That is to say a view doesn't know that it is displaying a Contact, it simply knows that it has, for example, 3 labels, 3 textboxes, and 2 buttons that are organized in a vertical fashion. Switching between views is tied to the history management within the presentation layer.
The views in our Contacts application are:
The EditContactView will be used to add new contacts as well as editing existing contacts.
A presenter contains all of the logic for our Contacts application, including events that are sourced from the UI widgets within the view.
For our sample we have the following Presenters:
Just as with the view, the EditContactPresenter will add new contacts as well as editing existing contacts.
To handle logic that is not specific to any presenter and instead resides at the application layer, we'll introduce the AppController component. This component contains the history management and view transition logic. View transition is directly tied to the history management and is discussed in greater length below.
PS: I thought this is a very good and instructive article, so I got it from GWT blog site, to be able to expose to more developers :-)
Other interesting resource: Organizing Complex GUI Applications for Test-Driven Development