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
-~----------~----~----~----~------~----~------~--~---