Does Presenter in Model-View-Presenter create views?

大憨熊 提交于 2019-11-28 03:29:09
Marijn

It depends ...

The main goal of MVP is to separate complex decision logic from UI code in such a way that both become easier to understand and to maintain. Often another goal is to make the decision logic in the presenter testable.

The MVP pattern was described by Fowler in 2004 and he retired it in 2006 by splitting the pattern into Supervising Conroller (SC) and Passive View (PV). In SC, the View is bound to the Model but not in PV; in PV, the View is only changed by the Presenter directly.

In both SC and PV, the Presenter has to update the View and react to changes the user made to the View, such as entering text or pressing a button. When you let the View call methods on the Presenter, then the problem you describe arises because the View needs a reference to the Presenter and vice versa. If you do this, you simply can make a decision who starts it all up. Options are:

  1. The View creates an instance of the Presenter. When the View is loaded, it passes itself to the Presenter in an initialize function on the Presenter.
  2. The other way around: Presenter creates View and passes itself to the View in an initialize function on the View.
  3. You introduce a third object that creates both View and Presenter, wires them together and initializes them both.

All options allow you to reach "MVP goals" of separation of concerns and increased testability of decision logic. I don't think any of these methods is theoretically right or wrong –you just have to pick the one that is most appropriate to the technology you use. And it's best to be consistent in your choice throughout the application.

Neil McGuigan

These are your options:

var cvp = new ContactViewPresenter(new ContactView());

ContactViewPresenter constructor sets this.view = viewParam, and sets this.view.presenter = this. It keeps the code in the Presenter, it can swap out views if necessary, and it could pass in a mock of the view for testing.

var cv = new ContactView(new ContactViewPresenter());

ContactView constructor sets this.presenter = cvpParam, and this.presenter.view = this. Some logic in View, but not a lot. Can swap out presenter if necessary.

ContactView cv = new ContactView();
ContactViewPresenter cvp = new ContactViewPresenter();
cv.presenter = cvp;
cvp.view = cv;
cv.init();
cvp.init();

This is a lot more code.

ContactViewPresenter cvp = new ContactViewPresenter();

Constructor creates sets this.view = new ContactView() and this.view.presenter = this.

ContactView cv = new ContactView();

Constructor sets this.presenter = new ContactViewPresenter() and this.presenter.view = this

The last two seem a bit too coupled.

One is nice in that the code stays in the Presenter, and seems to allow for easier testing.

Two is nice in that you don't have to care about the Presenters too much and can worry about your Views more.

I don't think the Presenter should instantiate the view, that should be done by an entity (not in the data-oriented sense, I mean a general entity) outside of the MVP triad. For example, an Inversion of Control (IoC) framework (if you haven't heard about IoC, check Martin Fowler's article), or some application module responsible for user configuration.

If you are using WebForms then the WebForm OnLoad or Init should be the place where you create the Presenter - this is then passed an interface reference to the View which the WebForm implements.

So, something like this:

Presenter _presenter;

OnLoad(object sender, EventArgs e) 
{
  _presenter = new Presenter(this);
  _presenter.Initialise();
}

And the Presenter constructor is defined thus:

public class Presenter
{
  public Presenter(IView viewReference)
  {
    _viewReference = viewReference;
  }
}

I may have the terminology slightly wrong but I think you need to identify the composition root of your interaction; what is the thing that begins the interaction?

In the Webforms example I gave, the Webform is created by the Http pipeline, the OnInit or OnLoad event is the first point in the pipeline ( depending on what context you need ) that you can 'hook in' to the process. Thus, you create a Presenter and give it your concrete instance of a Webform as a View Interface.

I don't know the Javascript frameworks you are discussing but I presume there is an initialisation / invocation step - in ASP.NET MVC this is when an ActionInvoker gets involved, it's the Main in a Console App.

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