On your mark, get set, present! - codecentric AG Blog

:

In my inner dialog about GWT I mentioned that we used Model-View-Presenter approach in our project – MVP plus event bus mechanism. It is quite interesting approach, could be labeled as overhead, but it is with no doubt useful. This time, I would like to write a bit more about how we organized our presenters and views, and how we incorporated it with history management – all of that with little help from Google Gin.

So, there is a Presenter, a View and a Model. We should not care about what model brings – it is just some data. View is a place where that data is shown, presented. Presenter is the one responsible for fetching and presenting that data. Naturally, there has to be some sort of relationship between the presenter and view class – every presenter class knows about the view it is responsible for. Here is the small fragment of code just for illustration:

public class ContactViewPresenter extends Presenter {

public interface Display extends PresenterDisplay {

}

protected Display display;

@Inject

public ContactViewPresenter(Display display, EventBus eventBus, DispatchAsync dispatcher) {

super(eventBus, dispatcher, HistoryPlace. EDIT_CONTACT_PAGE);

this.display = display;

}

}

public class ContactView implements ContactViewPresenter.Display {

}

As it can be seen, display, the view, is injected into the presenter and represents the bridge between those two. Event bus is also injected, in order to make presenter able to listen and fire different types of events. Third thing being injected is dispatcher used for dispatching asynchronous calls.

When we started working on this, our goal was to make presenter classes able to realize when is the moment to present their display. Basically, we were trying to avoid having one class that will tell every single presenter things like “showDisplay” and “hideDisplay”. We wanted to make presenters independent and “self aware”. For deeper understanding how it is done, we should take a look at class Presenter, since every presenter in our application extends it:

public abstract class Presenter implements ValueChangeHandler<String> {

protected EventBus eventBus;

protected DispatchAsync dispatcher;

protected HistoryPlace place;

public abstract void refreshDisplay();

public abstract void clearDisplay();

protected abstract void bind();

protected abstract void unbind();

@Override

public void onValueChange(ValueChangeEvent<String> event) {

}

}

Beside having injected event bus and dispatcher, every presenter has knowledge about what “history place” it is responsible for. HistoryPlace is enumeration that links currently presented display and application’s URL: every history place is defined by one history token. This means when specific history token (HistoryPlace) is part of application’s URL, corresponding display should be presented.

How our presenter knows that the time has come to present its display? Every presenter class is able to register itself as listener of “history change” events (since it extends Presenter that implements ValueChangeHandler<String>) – every presenter listens to the history events. When such event is fired, by calling History.newItem(), method onValueChange is called and there is where presenter determines if time to react has come: it simply compares HistoryPlace, or history token if you like, that’s its responsibility with the one from the ValueChangeEvent. If those are equal, it’s time to present – method calls its bind() method (registers all event bus listeners, handlers and other smart stuff) and its refreshDisplay() method (fetches desired data – Model); if not, presenter stays inactive.

Well, not completely inactive… Once the bind() method is called, many event handlers and listeners are added into the event bus. In our case, event bus has single instance used across the application causing that after presenting some displays several times, i.e. calling bind() method (of different presenters) several times, there will be multiple handlers and listeners for same sorts of events (originating in different presenter classes) registered into the event bus. No one wants that because it would be very difficult to understand what is happening in the background, what and why are doing presenters which displays are not currently visible.

For that reason there is unbind() method. Once presenter realizes that requested display, via HistoryPlace, is not its dedicated one, it checks if the current one is. If yes, it calls its unbind() method and removes all unnecessary handlers and listeners from the event bus. If not, it stays inactive. This time for real.

It wasn’t clear how the solution will look like from the start, but the idea and wish what we want to have was. It was developed gradually, iteratively redesigned and step-by-step improved. Java background of GWT and Java way of thinking definitely added value to this part of development – it made us think, (re)design and (re)organize our code. Having in mind the complexity of it, I doubt we would come to such a nice solution if we used plain JavaScript.