On Jun 4, 1:44 am, Jiang Zhu <[email protected]> wrote:
> When I looked at MVP related articles, demos and so many
> implementations, I keep ask myself following questions.
>
> (1) How to make Place definition simple yet flexible?
> (2) How to elegantly decouple presenters and decouple a presenter and
> it's container and it's children presenters?
> (3) What is the responsibility of Place Service (or Activity Manager
> in GWT2.1)? and what does the API look like?
>
> Since I struggled so long to try to find the answers, I'd like to
> share what I got so far (I've written a Place Service implementation).
> My own humble opinion regarding these questions are:
> (1).
> Most of time, place can be just a string but some times it need to
> carry parameters or even extend from other places. Therefore, a Place
> should be an interface instead of concrete class so enum can be used
> to define simple static places.
>
> public enum Pages implements PagePlace, GenericPlace {
> HOME, HELP, SECURITY_PERMISSION, SECURITY_ROLE // ...
>
> @override
> public String getHistoryToken() {
> return name().toLowerCase();
> }
>
> }
>
> There are places which carry history tokens but some are not, for
> example, header and footer of application are places but does not
> require history token.
>
> public enum CommonComponents implements ComponentPlace {
> ROOT, HEADER, FOOTER, TOPMENU, SUBMENU, HELPCENTER, MAIN
>
> }
Your notion of place seems to encompass both "what" to show/do
(activities) and "where" to do it (placeholders in your widget
hierarchy where to put views in).
If you limit places to "activities", there's almost always a 1:n match
(one activity responding to different tokens, where the token contains
some data identifier, parameter/argument, etc.)
I agree with Tristan about the non-extensibility of enums, but I don't
see an issue with it (haven't come across a use case, yet).
> For the places need to carry a parameter, it'll need to be defined as
> a class instead of enum.
>
> public class IdentifiablePlaceExample extends IdentifiablePlace
> implements PagePlace, GenericPlace {
> // Runtime place instance will use this constructor to create
> place with identifier
> public IdentifiablePlaceExample(String identifier) {
> this.identifier = identifier;
> }
>
> // Return history token for Browser - #!(token):(identifier) will
> be displayed in browser url
> @Override
> public String getHistoryToken() {
> return "history-token-you-want";
> }
FYI, my implementation decouples history/place bidirectional mapping
from places. This is implemented in a HistoryMapper that the app
provides to the PlaceManager.
> (2).
> In my opinion, a presenter should NOT attach the corresponding view to
> DOM or a container presenter itself.
>
> public interface Presenter {
> public Viewable bind(Place place);
> public void unbind(Place place);
>
> }
>
> public interface Container extends Presenter {
> public void showChild(Place place, Viewable childView);
> public void closeChild(Place place, Viewable childView);
>
> }
>
> In my Place Service implementation, Place Service knows the dependency
> between presenters but not presenter themselves. Therefore, when a
> view been required, Place Service will call the Presenter.bind(Place
> place) function to ask the corresponding Presenter to provide a View
> instance.
>
> After that, Place Service will find out which Container (a special
> type of Presenter) is responsible for displaying that type of Place
> and call Container.showChild(Place place, Viewable view) function to
> let the Container handle displaying the view in the container view.
> E.g. display a particular tab page (The View returned by the
> Presenter) in a tab container (The Container presenter).
>
> This way, in my main presenter which handles multiple children pages
> will no longer need to know any of other presenters but a generic
> Place type.
Er, why couldn't the Container itself do the place/child mapping? The
main difference with many other "place service" implementations
(including mine) is that yours doesn't use events (to which listeners,
including some kind of app controller or activity manager, choose how
to handle) but instead rely on configuration (BTW, does it accept
Provider<?> for lazy init?).
This (how you modeled containers) is also where your places start to
become placeholder/region identifiers instead of "overall places", and
where containers are hardly more than container widgets (which
wouldn't need MVP)
My definition of "place" is the answer to "where am I?" when you look
at the whole viewport/window. When typing this, I'm looking the thread
on Google Groups. If I were in GMail, I could be viewing "the
conversation in the 'GWT' label", or "the conversation in the inbox".
In Google Reader, I could have seen your message in "this group's
feed", or the "all items" view.
In my app (which by no mean implies I'm right!), containers handle all
"place change events" for places of their child presenters (which they
know by name) too. To make this easier, I'm just using a hierarchy of
interfaces. For instance, our app has 2 main tabs, one for document
management (with an explorer-style UI) and one for workflows (with a
mail-style UI, with an inbox, outbox, etc.). For workflows, I have a
base WorkflowPlace, inherited by WorkflowListPlace and
WorkflowDetailsPlace (with the workflow ID); the WorkflowListPlace is
implemented by an enum with INBOUND, OUTBOUND, DRAFTS, ALL, etc. The
main presenter switches to the Workflows tab as soon as a
PlaceChangeEvent fires for a WorkflowPlace. The "workflows" presenter
switches its left pane, and for a WorkflowListPlace highlights the
according "tab" (similar to the "inbox", "drafts", etc. in GMail).
Finally the workflow details presenter uses the place's ID to retrieve
the workflow data (I have a workflow list presenter instance per
WorkflowListPlace)
This might not be ideal but it works pretty well, and maps well to my
definition of "places" too.
--
You received this message because you are subscribed to the Google Groups
"Google Web Toolkit" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/google-web-toolkit?hl=en.