Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GWT MVP with Places & Activities - Where's the Model?

Tags:

mvp

gwt

I'm trying to familiarize myself with the "Places & Activities" design pattern for GWT development, and so far I think it has a lot of potential. I especially like the way how once you start thinking about your application in terms of "Places", browser history virtually just lands in your lap with almost no extra effort.

However, one thing just bothers me: All the articles and code examples I've seen so far gloss over one (as far as I am concerned, major) aspect: the 'M' part of the 'MVP', i.e. the Model!

In normal MVP architecture, as far as I understand it, the Presenter holds a reference to the Model, and is responsible for updating it according to UI events or, respectivly, updating the UI according to Model changes.

Now, in all the articles/samples for "P&A" the Activities seem to be taking the place of the Presenter, but unlike 'normal' Presenters, they get discarded and (re-)created whenever a new Place arrives, so they can't be the ones to store the client state, or it would be lost every time. Activities are cheap to create, so it's not much of a hassle, but I wouldn't want to create the model of a complex application over and over again.

All the samples are fairly simple and don't have much of a state and therefore just ignore the Model aspect, but where would an actual, complex application store its state?

like image 535
Andreas Baus Avatar asked Apr 01 '11 07:04

Andreas Baus


2 Answers

I think I found my own answer. The main problem seems to be that all of the simple code examples make the Activities be the Presenters, as in:

public class NavigationActivity extends AbstractActivity implements NavigationView.Presenter {
    private final ClientFactory clientFactory;
    private final NavigationPlace place;

    public NavigationActivity(ClientFactory clientFactory, NavigationPlace place) {
        this.clientFactory = clientFactory;
        this.place = place;
    }

    @Override
    public void start(AcceptsOneWidget panel, EventBus eventBus) {
        NavigationView navView = clientFactory.getNavigationView();
        navView.setSearchTerm(place.getSearchTerm());
        navView.setPresenter(this);
        panel.setWidget(navView);
    }

    @Override
    public void goTo(Place place) {
        clientFactory.getPlaceController().goTo(place);
    }
}

Now Activities are fairly short-lived, whereas a typical Presenter in the 'classical' sense has a much longer lifespan in order to maintain the binding between the model and the UI. So what I did was to implement a separate Presenter using the standard MVP design pattern, and all the Activity does is something like this:

public class NavigationActivity extends AbstractActivity {
    private final ClientFactory clientFactory;
    private final NavigationPlace place;

    public NavigationActivity(ClientFactory clientFactory, NavigationPlace place) {
        this.clientFactory = clientFactory;
        this.place = place;
    }

    @Override
    public void start(AcceptsOneWidget panel, EventBus eventBus) {
        NavigationPresenter presenter = clientFactory.getNavigationPresenter();
        presenter.setSearchTerm(place.getSearchTerm());
        presenter.go(panel);
    }
}

So, instead of the Activity fetching the View, and acting like a Presenter on it, it fetches the actual Presenter, just informs it of the client state change induced by the Place, and tells it where to display its information (i.e. the view). And the Presenter is then free to manage the view and the model any way it likes - this way works a lot better (at least with what I have in mind for the application I'm working on) than the code examples I have found so far.

like image 176
Andreas Baus Avatar answered Nov 11 '22 01:11

Andreas Baus


You're right, almost always the presenter is the only guy holding the model and managing its lifetime. Model from previous GWT versions has simply been a DTO, (and continues to be) a POJO which are created by the GWT deserializer when RPC methods return, or created by Presenters and filled with UI data by UIHandlers, and sent to the server.

I have taken efforts, to keep the Models lifetime encapsulated within the Activities lifetime, and avoided storing state outside of activities. (I do however have a singleton Global State maintained for use from anywhere in the application.) This I think is what GWT MVP engineers assumed will happen - It makes sense when, say the user has navigated away from a Place, for the models associated with that place also to get disposed (& collected). Create models, fill them up inside the activities, and make service calls to update the server before navigating away (or triggered by some control on the page), and let them go along with the activity - is what I have been doing till date.

A bigger project I have been involved in faced quite a few browser memory footprint issues, and all of them were due to objects which are associated with another (not currently viewed) Place being in memory. It was hard to track and remove references to these objects, and since the user has navigated away from the screen - the "why are my old screen objects still in memory?" question cropped up frequently and subsequently got fixed. This is why, upfront, I chose to keep the Model's lifetime encapsulated within the Activities lifetime in my current pet project.

If you have models that span across (that are filled/accessed by) several activities (as is the case if you have sidebars & master/container widgets), some redesigning of models maybe in order, if you have examples I will try and help.

like image 9
Zasz Avatar answered Nov 11 '22 00:11

Zasz