MVP Pattern in GWT: How to initialize Model/View and handle server requests in the Presenter?

旧巷老猫 提交于 2019-12-13 06:05:24

问题


This question isn't necessarily GWT bounded but on the other hand this comes right from my attempt to use it correctly.

I am using the MVP pattern (as recommended) in GWT but I am not sure how to deal with the model and the view as well as I am not quite sure how to create requests to the server. In particular I would like to know

  • Where do I initialize MyView? Does the presenter do that by itself in the constructor or does it receive a valid reference as parameter to the constructor?
  • The same with MyModel. As the instance of MyModel might be shared among different presenters I guess it should be passes to the presenters constructor.
  • How do I make requests to the server in the presenter? Do I have an additional layer that will handle my request or is it recommended to use MyServletAsync right there as well?

I'm having a hard time figuring out a good design. See below an example code that shows how I am doing it now:

public class MyPresenter implements MyView.MyPresenter

    private final MyServletAsync myService = MyServlet.Util.getInstance();

    private MyModel myModel;
    private MyView myView;

    public MyPresenter(MyView myView, MyModel myModel) {

        this.myView = myView;
        this.myModel = myModel;

        // Register click handler ..

        this.myView.getNextXyzButton.addClickHandler(
            new ClickHandler() {
                @Override
                public onClick(Event event) {
                    requestXyz(this.myModel.getXyz().getOffset() + 1);
                }
            });

        this.myView.getPrevisousXyzButton.addClickHandler(
            new ClickHandler() {
                @Override
                public onClick(Event event) {
                    requestXyz(this.myModel.getXyz().getOffset() - 1);
                }
            });

        // Initialize Xyz with offset 0
        requestXyz(0);
    }

    /*
     * Should I do this here in the presenter or should I 
     * create another layer that handles requests?
     */
    private void requestXyz(final int byOffset) {
        myService.getXyzFromServer(byOffset, new AsyncCallback<XyzDto>() {
            @Override
            public void onSuccess(XyzDto result) {
                updateModelWithResult(result);
            }
            @Override
            public void onFailure(Throwable caught) {
                displayError(caught);
            }
        });
    }

    private updateModelWithResult(Xyz result) {     
        this.myModel.setXyz(result);
        this.myView.displayXyz(result);
    }

    private displayError(Throwable caught) {
        // ..
    }

}

Thank you for any advice.


回答1:


The MVP pattern is great, and it's designed to isolate but mediate totally different things. However, the pattern does not dictate how it's implemented and it's all on your own, but respecting some aspects, sure. Out of my experience, I would say that:

Where do I initialize MyView?

A presenter is better to accept some kind of a view factory (or a supplier in general as we can already hold an existing view, especially in a GWT case), and let the presenter decide when instantiate or accept the view. My current project uses a small custom library that defines an abstract presenter and this is how it's implemented:

public abstract class AbstractPresenter<M extends IModel, V extends IView>
        implements IPresenter<M, V> {

    private final M model;
    private final V view;

    protected AbstractPresenter(final M model, final IViewFactory<V, ? super IPresenter<M, V>> viewFactory) {
        this.model = model;
        view = viewFactory.createView(this);
    }

...

}

The main reason of passing the view factory is injecting the presenter to the view as views mostly should have references to their respective presenters (+ I prefer to have final fields, so this is a way of having both final references: presenter to view, and view to presenter).

I guess it should be passes to the presenters constructor.

Yes, it may be passed via a constructor like in the example above, however some people may prefer set-accessors like setModel and setView.

How do I make requests to the server in the presenter?

This is what model is for. A presenter is only a mediator between a model and a view, and it's basically only responsible for user interaction in both directions. Consider your model is a way to access your application, as a model should not be considered a dummy "get/set fields" object. Model is an abstraction over service layers, network communication (can be an abstraction behind a service), data storage, or whatever your application has. Thus, your presenter just has to notify the model for getting or putting some data (from/to elsewhere respectively). Also this allows you to write fully abstract layers. If you do unit testing, then you're in trouble for testing your presenter due to private final MyServletAsync myService = MyServlet.Util.getInstance(); requiring the servlet to be up (a bad idea, right?). So if getXyzFromServer becomes a part of the model (I would say, then it might be named getXyz because the presenter does not really cares where the Xyz is fetched from), you can easily mock your model and just test the pure presenter.



来源:https://stackoverflow.com/questions/32146099/mvp-pattern-in-gwt-how-to-initialize-model-view-and-handle-server-requests-in-t

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!