Thomas, I need to think more about this approach. Ray mentioned in his talk about having too many events and performance. Does your approach not lead to that?
-mic On Apr 1, 3:16 am, Thomas Broyer <[email protected]> wrote: > On Apr 1, 1:15 am, Nathan Wells <[email protected]> wrote: > > > Thomas, > > > I've heard of your approach before, but I'm not clear on the > > implementation... are you passing the presenter itself into the view? > > or are you passing instances of event handlers? The difference seems > > trivial, but in practice (as I imagine it, anyway) seems large: > > >http://etherpad.com/sIAaiCfuiG > > > Let me know what you think. I would assume the first way is what your > > referring to in your comment above, which implies that it is a View > > layer responsibility to deal with HandlerRegistrations and the like. > > Is that correct? > > Yes. It makes a few things much easier for me: > - I can use @UiHandler in the view, which makes the whole thing more > readable (on the down-side, I used to create a class that implement > all required handlers instead of using an anonymous class per handler; > UiBinder doesn't do this optimization (yet?) with @UiHandlers) > - I can use event delegation in the view > - The view methods are more "consistent" (get/setUserName and > setUserNameEnabled(boolean), vs. getUserName->get/setText and > setUserNameEnabled(boolean); this elad people to ask for a HasEnable > interface, which wouldn't solve anything as you'd still need > getUserName->HasText and getUserNameEnablable->HasEnable), even more > when also dealing with non-widget UI elements: I implemented a login > form with a <form> in the HTML page which action="" is set to callback > a GWT method ($wnd.__form_callback = $entry([email protected]())) and > had to create a dummy HasClickHandlers to return as the > "HasClickHandlers submitButton()"; with a Listener is way easier: the > onSubmit just calls back the listener.submit(). > - I have one "screen" where the user can add files to upload, each > "file" is a line composed of a FileUpload and a "cancel" button next > to it that removes the "line" from the screen (and therefore "cancels > the file" before the form is submitted), already uploaded files > (unpredictable number) are shown as a label with a "delete" button > next to it. Add to this that files are grouped into dynamic, > unpredictable "groups". Previously, I did everything with a > SelectionEvent<String> where the value was something like "add:<file > group>", "cancel:<file id>", or "delete:<file id>" (I use event > delegation in the view). Now, instead of firing a SelectionEvent with > a specific value, I just call the listener's addFile(String group), > cancelFile(String fileId) or deleteFile(String fileId). > Sure I could have defined new events instead of doing it all through a > SelectionEvent but it wouldn't have make things much easier, with more > files to maintain. > > As for the implementation, I currently have something like: > public class FooPresenter { > @ImplementedBy(FooView.class) > public interface Display { > void setListener(Listener listener); > > void setThisVisible(boolean visible); > > void setThatEnabled(boolean enabled); > } > > public interface Listener { > void save(); > > void close(); > } > > private class Handlers implements PlaceHandler, > SomeOtherBusEventHandler, Listener { > ... > } > > @Inject > public FooPresenter(Display view, EventBus bus) { > Handlers handlers = new Handlers(); > bus.addHandler(PlaceEvent.getType(), handlers); > bus.addHandler(SomeOtherBusEvent.getType(), handlers); > view.setListener(handlers); > } > > ... > > } > > public class FooView implements FooPresenter.Display { > @UiField Button save; > @UiField Button close; > > private FooPresenter.Listener listener; > > ... > > public void setListener(FooPresenter.Listener listener) { > assert listener != null; > this.listener = listener; > } > > @UiHandler("close") > void onCloseClick(ClickEvent event) { > listener.close(); > } > > @UiHandler("save") > void onSaveClick(ClickEvent event) { > listener.save(); > } > > } > > I'm using a Listener *interface* so the view doesn't have direct > dependencies on the presenter's behavior (I could therefore mock a > Listener and make a small app to "manually test" my view without > actually having any presenter, event bus, etc.) > > I decided to switch to this design instead of HasXxxHandlers when I > saw Ray's work on RequestFactory: """In the Wave style: the view > (editor) has a single listener for its semantic operations.""" > The main difference is that I do not have an interface for each > presenter with its impl class (interface FooPresenter / class > FooPresenterImpl implements FooPresenter, FooPresenter.Listener) so my > presenter class doesn't itself implement the listener interface (it > would also "pollute" its public API, which is not a problem in Ray's > case where no other object has a direct dependency on the Impl class, > only on the presenter interface). > In a new project we're starting, I might reconsider this approach > though, and introduce an interface vs. impl class dichotomy all over > the place. > > Something to be aware of though: the Listener approach puts a bit more > responsibility into the view than the HasXxxHandlers approach, but > it's so much easier to work with (and write unit tests) that's I think > it's worth it. -- 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.
