For the past eight(8) years Schalk Neethling has been working as a freelance developer under the pseudo of Volume4 and is now the president of Overt Strategy Consulting. During this period he has completed over 300 projects ranging from full web application development to complete branding. As president and lead developer of Overt Strategy Consulting, Schalk Neethling and his team has released a 100% Java standards based content management system called AlliedBridge and business document exchange and review system, called Doc-Central. Schalk Neethling is also actively involved on a daily basis in the open source, web standards and accessibility areas and is a current active member of the Web Standards Group. Schalk is also the co-founder and president of the non-profit The South Web Standards and Accessibility Group, which aims to actively educate and raise awareness of web standards and accessibility to both the developer society as well as business large and small. Schalk also has a long relationship with DZone and is currently zone leader for both the web builder, css.dzone.com, as well as the .NET zone, dotnet.dzone.com, and you can find a lot of his writing there as well as on his blog located at schalkneethling.alliedbridge.com. Schalk is constantly expanding on his knowledge of various aspects of technology and loves to stay in touch with the latest happenings. For Schalk web development and the internet is not just a job, it is a love, a passion and a life style. Schalk has posted 173 posts at DZone. View Full User Profile

Design patterns and GWT

07.21.2008
| 64308 views |
  • submit to reddit

We have a calculator EntryPoint implementation that places a CalculatorWidget on the RootPanel, so we now need to provide this widget. This will be our own widget, composed of basic GWT components. CalculatorWidget will contain the view for our calculator application, a simple data and logic layer as the model, and an intermediary controller between these layers. This, of course, means we'll be using MVC and GWT together - keep in mind that all of these components will end up distributed to the client.

MVC will be the overarching pattern for the macro level of our application. Additionally, we'll use some other common object-oriented (OO) patterns on other levels because of the general benefits these approaches provide. For example, we'll use the Observer pattern for event handling as part of the mechanism of communication between our model and our view. We'll also use the Strategy pattern within the logic and operations parts of our model. We'll provide more detail about each of these patterns, and the reasoning behind their use in each situation, as we come to those portions of the application.

The most important pattern we need to consider is MVC itself. This pattern is the most useful we have found for creating GWT applications, while still keeping them manageable and testable.

MVC and GWT

MVC is a familiar pattern to many developers. The pattern was first described in the late 70s by Trygve Reenskaug, who was working on Smalltalk at the time, and it has since been adopted, in various forms, by a wide range of programmers using many languages. The pattern is intended to separate responsibilities and allow for reuse of the logic and data portion of an application' the model. The view layer represents the model graphically, as the UI. Delegation between these layers is handled by an intermediary that is invoked by the user's input, the controller. The basic MVC pattern is shown in figure 1.

Figure 1 A basic model-view-controller architectural pattern diagram. The solid lines indicate a direct association, and the dashed lines indicate an indirect association, such as through an observer/observable relationship.

The key concepts to take away from MVC are the following: the model should be completely unaware of the view and controller, and the pattern can be applied on many different levels within an application.

In MVC, the model can be equipped to alert observers of changes within it, using the Observer pattern (something we'll look more closely at in the section on communicating by observing events). This is shown by the dashed line in figure 1. In this way, any other layer observing the model can react to events coming from the model. Nevertheless, the model does not directly update the view, and this distinction is important. The model is the reusable part in all incarnations of MVC; if the model had any direct knowledge of the view, that tenet would break down. How the view and controller are linked together is often more variable.

The view typically has a reference to the controller, and may invoke controller methods directly, based on user input. The controller ideally will have no direct references back to the view, and should simply update the model. If the view is an observer of the model, this effectively updates the view without direct controller/view coupling. Alternatively, it's also common to see situations in which the controller and view are treated as a pair, with direct references from the controller to the view.

There are many ways to divide up the responsibilities, and the various approaches have their pros and cons. The important part, though, is that the separation of responsibilities makes the code clearer, and often also makes testing easier. MVC can be applied with GWT, and it can happen on many different levels. An overall application may have a master domain, or model, and an overarching controller. Individual widgets can have their own encapsulated MVC, and small elements, such as a button, can repeat the pattern on their own level.

The possible variations of MVC, and many somewhat similar GUI architectural patterns, such as Presentation Abstraction Control (PAC) and Model View Presenter (MVP), are very interesting but are beyond our scope here. Fortunately, entire tomes on the subject exist. For our purposes, we’ll turn to concrete examples of MVC that we have found work well with GWT. To do this, we need to get into code and implement the pattern.

Creating a widget

The functional specifications for a calculator (at least a simple one) are fairly universal; they include a display, some buttons, and some mathematical operations defined by the likes of Pythagoras and Euclid. For our calculator, we'll make use of one GWT TextBox for the display and many GWT Buttons for, well, the buttons. We'll also use a layout derived from a Panel and a Grid to control the overall placement of the UI items. In terms of MVC, view elements are where all widgets begin, starting with the layout. The model and controller for our calculator will be implemented as separate classes that are referenced by the widget.

With GWT, you use widgets to create your application. These components are built from layout panels, input elements, events, data objects, and various combinations thereof. This is where GWT really departs from typical web applications and may seem somewhat foreign to those accustomed to standard server-side Java development. To create an application, you use widgets that are capable of being inserted or removed from the screen, in a single page, on the client side.

For our purposes, we'll extend the GWT-provided VerticalPanel component to build our view, and then include references to our separate controller and model, as shown in the class diagram in figure 2.

Figure 2 CalculatorWidget top-level class diagram showing the extension of GWT's VerticalPanel as the view, and the included model and controller references

It's worth noting that figure 2 does not display all the attributes or operations of the CalculatorWidget class. We have included just a representative sample of attributes to keep it concise. The code for the CalculatorWidget will be displayed in three parts in listings 1, 2, and 3. Listing 1 addresses the beginning of the class, showing what the class needs to import and how the class is derived from, and makes use of, other existing GWT classes.

Listing 1 CalculatorWidget.java, part one:

package com.manning.gwtip.calculator.client;

import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.TextBox;

//. . . remainder of imports omitted

public class CalculatorWidget extends VerticalPanel {
private TextBox display;

public CalculatorWidget(final String title) {
super();

final CalculatorData data = new CalculatorData();

final CalculatorController controller =
new CalculatorController(data);

//...

Within the first part of the CalculatorWidget class there are several important items. First of all, we're making use of some existing GWT client.ui classes to compose our view . Our entire class is, in fact, a subclass of VerticalPanel . This is significant in that we inherit all of the hierarchy of a GWT UI Widget automatically with this approach.

Directly extending a panel in this manner is simple (in this case, intentionally so), but it's also limiting. It's often better to use a GWT Composite. We're using direct subclassing here to keep things very basic, and we'll move on to Composite in due course.

In listing 1 we then go on to define a simple constructor, and within it we create an instance of CalculatorController . CalculatorController itself will be addressed in the section on controlling the action, after we complete the CalculatorWidget class. The controller we'll be using is a client-side component, which itself contains a reference to the data portion of our model, which is a single CalculatorData object. That takes us to part two of the CalculatorWidget class: layout and buttons. These view elements are displayed in listing 2.

Listing 2 CalculatorWidget.java, part two:

VerticalPanel p = new VerticalPanel();
p.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
p.setStyleName(CalculatorConstants.STYLE_PANEL);

Grid g = new Grid(4, 5);
g.setStyleName(CalculatorConstants.STYLE_GRID);

final Button zero = new ButtonDigit(controller, "0");
g.setWidget(3, 0, zero);

final Button one = new ButtonDigit(controller, "1");
g.setWidget(2, 0, one);

final Button two = new ButtonDigit(controller, "2");
g.setWidget(2, 1, two);

//. . .

final Button divide = new ButtonOperator(controller, new OperatorDivide());
g.setWidget(0, 3, divide);

final Button multiply = new ButtonOperator(controller, new OperatorMultiply());
g.setWidget(1, 3, multiply);

//. . .

final Button clear = new Button(CalculatorConstants.CLEAR);
clear.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
controller.processClear();
}
});
clear.setStyleName(CalculatorConstants.STYLE_BUTTON);
g.setWidget(2, 4, clear);

//...

In this second part of the CalculatorWidget class, we add components to our widget and add event handlers for those components. First, we create a GWT Grid , a component made of rows and columns that ultimately will be implemented as an HTML table. We'll use this to lay out our calculator buttons. Then we add our two different types of buttons: ButtonDigit and ButtonOperator . The digits on our calculator are implemented by our own class, ButtonDigit, which extends the GWT Button class. The operators are similarly implemented by our own ButtonOperator class. Once again, for the sake of brevity, we have not included the code for all the fairly self-explanatory buttons and operators.

We have yet to create ButtonDigit and ButtonOperator, which we'll do next, but the important thing to know at this point is that these classes both implement a ClickListener. This listener gets the control when the buttons are clicked, and it invokes a controller method. Listeners are common in component-oriented development and enable an event-driven approach. Various listeners, such as ClickListeners, OnChangeListeners, KeyboardListeners, and more are available in GWT. By using listeners in this way, the controller is notified to perform an appropriate action when any button or operator is pressed on our calculator.

About KeyboardListeners

In this example, we have not attached KeyboardListeners to our calculator, for brevity's sake. But, obviously, including them would be very useful for a calculator. They can be enabled by setting a default focus element and then attaching the listeners.

Finally, we also add a standard GWT Button for both our calculator's CLEAR and EQUALS functions. These buttons directly invoke methods on our controller instance without our own Button subclass. This is done with regard to CLEAR and EQUALS because these are special cases in terms of calculator buttons, as we shall see when we get to the controller in the next section. Before moving on, though, we need to implement the remainder of the CalculatorWidget, as shown in listing 3.

Listing 3 CalculatorWidget.java, part three:

// . . .

display = new TextBox();

data.addChangeListener(new CalculatorChangeListener() {
public void onChange(CalculatorData data) {
display.setText(
String.valueOf(data.getDisplay()));
}
});
display.setText("0");
display.setTextAlignment(TextBox.ALIGN_RIGHT);

p.add(display);
p.add(g);
this.add(p);
}
}

The final part of the CalculatorWidget class creates a GWT TextBox for our calculator's display area , and then adds that component and our Grid to an earlier created VerticalPanel, which is in turn added to the current instance of itself. This ensures that all of the items are visible when CalculatorWidget is used .

Getting back to event handling, we have also introduced a custom listener' our own CalculatorChangeListener interface . This is implemented as an anonymous inner class, and it connects our display widget (the view) to the data it represents (the model), through events.

These events are a manifestation of the Observer pattern. We'll now take a closer look at this relationship, because it's what facilitates the separate responsibilities in our MVC-powered GWT calculator.

Published at DZone with permission of its author, Schalk Neethling.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Adrian Mouat replied on Thu, 2010/10/21 - 6:11am

Nice article, but I think there are some potential issues:

 - the listener needs to be checked for null everywhere in the observable

 - there seems to be potential synchronization issues

 On a side-note, the sign-up for this site is obnoxious, it asks for several personal details and has an unusual idea of what an address is (you *have* to enter a number!).

 

Adrian Mouat replied on Tue, 2010/10/26 - 7:36am

See also this (google) article:

 http://code.google.com/webtoolkit/articles/mvp-architecture.html

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.