Search code examples
javaeventsgwtgwt-mvp

GWT MVP: HandlerManager EventHandler vs GUI EventHandler


I am using GWT MVP to develop an application. I saw we can have two kinds of event handlers in GWT MVP code, but I am not very sure about which kind should I use in which place:

1) HandlerManager (eventBus) EventHandlers (e.g. EditEventHandler below) in AppController:

eventBus.addHandler(EditEvent.TYPE,
      new EditEventHandler() {
        public void onEdit(EditEvent event) {
          doEdit(event.getId()); // this would open a new screen, call AsyncService etc
        }
      });

I understand, these kind of event handlers are used for handling application-wide custom events.

2) GUI/View Event Handlers (e.g. ClickHandler) in Presenter, where I handle the GUI event and then fire the application event to invoke its handler as below:

display.getList().addClickHandler(new ClickHandler() {
    public void onClick(ClickEvent event) {
      int selectedRow = display.getClickedRow(event);

      if (selectedRow >= 0) {
        String id = myDetails.get(selectedRow).getId();
        eventBus.fireEvent(new EditEvent(id)); // this in turn would invoke the EditEventHandler above
      }
    }
  });

Now, my questions are:

1) Why do we need to write EventHandler for application events (e.g. EditEvent), and not add that code directly in the associated GUI event handler (e.g. addClickHandler)?

2)Can't we write the code for opening new screen, calling AsyncService etc directly in GUI EventHandler method, such as onClick ?

3) Wouldn't that make your code more readable, as the event that is triggered and the work that needs to be done is all in one place i.e.Presenter and you don't have to go back and forth between your Presenter code and AppController code?


Solution

    1. You could do that and in a small applications this might probably be the right approach. However you will definately increase coupling between your GUI, business logic and the various components. You should envision your screens as independent units and avoid any coupling between those units. In the best case your screen which displays a list of records should know nothing about the other screens or any other components. It should only care about those records.
    2. Technically there is no reason why you can't call AsyncService in your GUI EventHandler. Just make sure you do it in your Presenter and not in your View. However the more complex your app gets the messier this approach might get. You will have many AsyncService calls sprinkled all over your various Presenters. It might be a better approach to group them in your AppController so there is 1.) one place to look for and 2.) you can easily test/mock all AsyncService calls in your AppController.
    3. Work that can be done inside a Presenter should also be done there without needing to go through AppController and back. However it still might make sense to put the AsyncService calls into your AppController because you might need to do some bookeeping (for example caching the results in LocalStroage, submitting other Events, etc) and/or notify other screens/components about the loaded data.

    Think of Events as messages. Here is an example:
    You have a View/Presenter pair for displaying a list of records (i.e. RecordListPresenter). The user clicks on the edit button on one of the records and you have a separate View/Presenter pair for editing the specific record (i.e RecordEditPresenter). Instead of having a reference from your RecordListPresenter to your RecordEditPresenter which would make them aware of each other and increase the coupling the RecordListPresenter sends a message to edit a record (Edit event). The AppController will act as a Mediator and open load the data and open the RecordEditEditor (it can also only fire an Event with the loaded data and the RecordEditEditor could reveal itself).
    But now imagine that you also have a HeaderPresenter for displaying some breadcrumb information (like which record it is editing). If you go the "eventless" approach you would need another reference in the RecordListPresenter and RecordEditPresenter to it to drive it. With Events those Presenters don't have to know that there is a HeaderPresenter. They just fire Events.

    Now in a complex app you might have many of those independend units.