Hi,

maybe useful maybe not. This is what I ended up doing (similar to
Etienne's 2nd suggestion but different):

// a document has an associated collection of files
// document editor contains the file editor

class DocumentEditorPresenter{

   interface Display{
      ....
      // the Document editor view takes file editor view
      void adoptDisplay(FileEditorPresenter.Display display);
   }

   DocumentEditorPresenter(Display display, ..., FileEditorPresenter
fileEditorPresenter, ....){
        // I ask the parent display to adopt the child display
        // get the display from the child presenter
       display.adoptDisplay(fileEditorPresenter.getDisplay());
       ....
   }

   void onBind(){
       // also call the child presenters onBind
       // what the file presenter is doing with event bus
       // and services is not the concern of doc presenter
       fileEditorPresenter.onBind();
       ....
   }

   void edit(DmsDocument document){
      // delegate file handling to child presenter
      fileEditorPresenter.edit(document.getFiles());
      ....
   }

}

There are quite a lot of options with MVP.

Cheers
Alen

On Aug 22, 2:22 pm, Etienne Neveu <[email protected]> wrote:
> Hi,
>
> *WALL OF TEXT BEGINS ;) *
>
> We also encountered this problem in our app.
>
> In our case, our root presenter did not need to hold references to our
> child presenter(s). In this case, you only need to solve the problem
> you mentioned: "If ContactView has EmailView injected, we get into a
> dilemma where we don't have the Presenter instantiated". So I did
> something like this:
>
> -------------------------
>
> We are using gwt-presenter. If you extend "WidgetPresenter" 
> (http://code.google.com/p/gwt-presenter/source/browse/trunk/src/main/j...
> ), you can do the following in your view:
>
> public class ContactView extends VerticalPanel implements
> ContactPresenter.View {
>
>         private final Provider<EmailPresenter> emailPresenterProvider;
>
>         @Inject
>         public ContactView(Provider<EmailPresenter> emailPresenterProvider) {
>                 emailPresenterProvider = emailPresenterProvider;
>         }
>
>         private Widget createEmailView() {
>                 return emailPresenterProvider.get().getDisplay().asWidget();
>         }
>
>         private void buildWidget() {
>                  add(new HtmlPanel("Hi there");
>                  // Create 3 different email views, with 3 different
> presenters instantiated
>                  add(createEmailView());
>                  add(createEmailView());
>                  add(createEmailView());
>         }
>
> }
>
> The problem is that you make your views aware of the presenters. But
> since you unit-test the presenters, it won't pose a problem while unit-
> testing.
>
> Another solution if you want to abstract the presenter from the view,
> would be to use a provider method in your GIN module:
>
> @Provides
> EmailWidget createView(EmailPresenter presenter) {
>    return presenter.getDisplay().asWidget();
>
> }
>
> and then inject a Provider<EmailWidget> in your view.
>
> Each call to emailWidgetProvider.get() will then create a new
> presenter (which gets injected with a new view), give it to the
> provider method, and return the associated widget to be used by the
> view. This solves the problem of "not having the presenter
> instantiated".
>
> -------------------------
>
> Now, this "simple case" works because we supposed our ContactPresenter
> does not need to access the EmailPresenters. You can avoid these kind
> of dependencies by communicating between the presenters through the
> eventbus. But you won't always be able to do so, and in the real world
> you will often want to be able to call methods on your child
> presenters.
>
> I think I would do something like this:
>
> public class ContactPresenter extends
> WidgetPresenter<ContactPresenter.View> {
>         public static interface View extends WidgetDisplay {
>                 void add(WidgetDisplay display);
>
>                 void remove(WidgetDisplay display);
>         }
>
>         private final Provider<EmailPresenter> emailPresenterProvider;
>
>         private Contact contact;
>
>         private Map<Email, EmailPresenter> emailMap = new HashMap<Email,
> EmailPresenter>();
>
>         public ContactPresenter(ContactView display, EventBus eventBus,
>                         Provider<EmailPresenter> emailPresenterProvider,
>                         ContactModel contactModel) {
>                 super(display, eventBus);
>                 this.emailPresenterProvider = emailPresenterProvider;
>
>         }
>
>         void onBind() {
>                 registerHandler(eventBus.addHandler(EmailAddedEvent.getType(),
>                                 new EmailAddedHandler() {
>                                         void onEmailAdded(EmailAddedEvent 
> event) {
>                                                 // should this 
> ContactPresenter handle this email?
>                                                 if 
> (contact.equals(event.getContact())) {
>                                                         
> addEmail(event.getEmail());
>                                                 }
>                                         }
>                                 }));
>                 
> registerHandler(eventBus.addHandler(EmailRemovedEvent.getType(),
>                                 new EmailRemovedHandler() {
>                                         void onEmailRemoved(EmailRemovedEvent 
> event) {
>                                                 // should this 
> ContactPresenter handle this email?
>                                                 if 
> (contact.equals(event.getContact())) {
>                                                         
> removeEmail(event.getEmail());
>                                                 }
>                                         }
>                                 }));
>
>         }
>
>         void addEmail(Email email) {
>                 EmailPresenter emailPresenter = emailPresenterProvider.get();
>                 emailPresenter.setEmail(email);
>                 emailMap.put(email, emailPresenter);
>                 display.add(emailPresenter.getDisplay());
>         }
>
>         void removeEmail(Email email) {
>                 EmailPresenter emailPresenter = emailMap.get(email);
>                 display.remove(emailPresenter.getDisplay());
>                 emailPresenter.destroy();
>                 emailMap.remove(email);
>         }
>
>         void onUnbind() {
>                 // handlers are de-registered by BasicPresenter superclass
>                 // since we called registerHandler() in the onBind() method
>                 for (Email email : emailMap.keySet()) {
>                         removeEmail(email);
>                 }
>         }
>
>         // Should be injected in the constructor with assisted inject or with
> a
>         // factory?
>         void setContact(Contact contact) {
>                 this.contact = contact;
>                 for (Email email : contact.getEmails()) {
>                         addEmail(email);
>                 }
>
>         }
>
> }
>
> class ContactView extends VerticalPanel implements
> ContactPresenter.View {
>
>         // Create the view and so on...
>
>         void add(WidgetDisplay display) {
>                 add(display.asWidget());
>
>         }
>
>         void remove(WidgetDisplay display) {
>                 remove(display.asWidget());
>         }
>
> }
>
> (some things might be missing, since I wrote that without any dev
> environment... but the main ideas are there)
>
> -------------------------
>
> All of this works because the Presenter has a getDisplay() method, and
> the WidgetDisplay has a asWidget() method returning the underlying
> widget. One would think that the asWidget() method is bad when unit-
> testing presenters, but you can simply return null in your
> WidgetDisplay mock.
>
> Actually, in our application, since we use SmartGwt, where the high-
> level component is a "Layout" instead of a "Widget" we created a
> LayoutPresenter and a LayoutDisplay (with a
> com.smartgwt.client.widgets.layout.Layout asLayout() method). We also
> have a WindowPresenter / WindowDisplay, where the WindowPresenter
> superclass handles some of the window logic (with a openWindow()
> method that calls bind() and then shows the window... and a closeWindow
> () that calls unbind() and then hides the window...).
>
> What do you think of this kind of architecture? I'm interested in
> other ideas and best practices as well.
>
> Regards,
> -Etienne
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"google-guice" 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-guice?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to