Factoring out common MVP services into a Service Facade
Posted by David Chandler on October 5, 2009
Shortly after adopting the Model-View-Presenter pattern, I found myself copying the same service call into multiple presenters, as both a navigation panel and a main content area can sometimes display the same information. I decided to factor out the repeated service calls into a Service Facade (for lack of a better name) and inject the facade into each presenter that’s needed.
@Inject public AddPrayerListPresenter(Display display, EventBus eventBus, PrayerListServiceFacade prayerListServiceFacade) { super(display, eventBus); this.prayerListServiceFacade = prayerListServiceFacade; bind(); }
Inside the service facade, I use constructor injection to get the event bus and dispatcher the same as in a presenter.
@Inject public PrayerListServiceFacade(final EventBus eventBus, final DispatchAsync dispatch, RoaModel roaModel) { this.dispatch = dispatch; this.eventBus = eventBus; this.model = roaModel; } public void refreshPrayerLists() { GWT.log("Calling actionFindLists", null); // Fire event that marks start of the service call so listeners // can show the AJAX wait thingy if desired eventBus.fireEvent(new RefreshingPrayerListsEvent()); dispatch.execute(new FindPrayerListsAction(), new AsyncCallback<FindPrayerListsResult>() { @Override public void onFailure(Throwable e) { GWT.log(e.getMessage(), e); Window.alert(e.getLocalizedMessage()); } @Override public void onSuccess(FindPrayerListsResult result) { eventBus.fireEvent(new PrayerListsModifiedEvent(result.getPrayerLists())); } }); }
The refreshPrayerLists() method contains the code that had been common to multiple presenters. There is one difference, however. When a presenter calls a service, it typically passes a DisplayCallback object, which gwt-presenter uses to call the view’s startProcessing() and stopProcessing() methods so you can show an Ajax wait thingy (er, progress indicator?) I could add a Display argument to the service method and create a DisplayCallback as usual; however, in this case, I want the refresh method to be called only once in conjunction with the event that necessitates a refresh (say, a new prayer list is added). And I want multiple widgets to be notified when the service call begins, and when it finishes. To accomplish this, I pass only a regular AsyncCallback object and fire an event both before and after the service call, to which any interested widget can listen.
In summary, the service facade provides a way to group all related service calls in one place and to factor out common calls from multiple presenters. Now all I need is a better name for it, as it sounds a little scary for my taste…
Matt Raible said
Now all I need is a better name for it, as it sounds a little scary for my taste…
I use a similar pattern on my project. I just call it a *Service and *ServiceImpl – allowing me to mock it out when writing tests with EasyMock.
David Chandler said
Thanks, Matt. I had wanted to avoid confusion with GWT-RPC services, but come to think of it, with gwt-dispatch, there’s only one real service, so there won’t be any naming confusion, after all. And the subtle suggestion to use an interface also is well-taken.
Darren said
Very neat. I’m finding your blog a very interesting read. 🙂
Roar Skullestad said
Just curios, how is RoaModel implemented? I see from another post that it contains a getLoginInfo() method. How does it use DispatchAsync? Does it always contact server or does it work like a cache?
David Chandler said
Sorry for late reply, RoaModel is just a cache for various other objects returned by service calls such as LoginInfo.
lost said
what exactly is a PrayerList ?!
David Chandler said
Think of it as a to-do list containing prayer requests shared by individuals and churches.