Does Presenter in Model-View-Presenter create views?
Asked Answered
R

5

32

How are Views created in MVP? Does the Presenter always create them (in addition to View in case of subviews)? Or is it a separate third-party component or App or something that creates them?

Let's also add that I'm probably going to do this on Dojo Toolkit/ExtJS (JavaScript that is).

So, I have these code lines:

var v = new MyApp.view.User();
var p = new MyApp.presenter.User();

where should both lines go exactly? Does the presenter instantiate the view, or vice-versa? And what instantiates the first instance?

Rabin answered 6/6, 2011 at 7:36 Comment(0)
S
50

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.

Sagerman answered 21/6, 2011 at 19:57 Comment(11)
I'd like to add some examples, but I'm not that good at Javascript, sorry,Sagerman
Thank you for the thoughts. It's hard to find information on these matters anywhere. I think I am leaning towards the third option. I have to plan and see if it works though. Do you have any good resources/links to share?Rabin
Yesterday I did a quick google search. I found this SO question interesting to read.Sagerman
Besides the links in my answer, I found the build-your-own-cab-series great in explaining the different flavors of MVP. It's specific to .NET though.Sagerman
In .NET, you'll typically define an interface for both view and presenter. (I don't think you have that option in Javascript?) This way you get strict decoupling between view and presenter. However it is no answer to your question about creation and initialization. The creation part can be done partially by using an IOC framework, but you'll only be able to inject the view on the presenter or vice versa. Assuming view and presenter have to reference each other, you'll still need a way to pass a reference using an initialization method introducing a similar problem as in your question.Sagerman
I have come to the conclusion that I will instantiate Presenter and View out of the MVP-triad. I have not yet decided which application component should be responsible for doing that. However, View will not know about Presenter. View will be firing events that Presenter (who knows View) can catch and act upon. Presenter will also listen to Model events and re-render View when needed.Rabin
That'll work - it's a valid, well known approach. When you take this "events" approach, you make the reference from view to presenter implicit (namely by the event handlers). In .NET I don't use this approach, because I find it hard to write unit tests for the presenter. In Javascript it might work very well - good luck!Sagerman
Many view-presenter combinations can be created as singletons by your dependency injection framework. Others pairs should be created by your event bus.Ackerman
See msdn.microsoft.com/en-us/magazine/cc188690.aspx for a detailed definition of MVP; essentially very much an MVC pattern although MVP truly separates the UI from the domain/service layer of the application.Dorina
While it is the best answer to the question, you have only answered part of the question, furthermore I feel that in many cases MVVM is a more pertinent design pattern with regards to JS and would have dissuade the asker from MVP, especially when used with something like Knockout.Dorina
[sp - "supervising conroller"]Monodrama
M
6

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.

Madelenemadelin answered 20/5, 2012 at 19:9 Comment(0)
A
2

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.

Aerogram answered 19/6, 2011 at 22:19 Comment(2)
When you choose to have view and presenter to hold a reference to each other, using an IOC framework doesn't help for non-singleton views and presenters.Sagerman
That being said, it can be helpful to have a third component instantiate the "mvp triad", for instance if you want to intercept calls to view and presenter.Sagerman
G
0

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;
  }
}
Gallman answered 6/6, 2011 at 8:19 Comment(0)
G
0

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.

Gallman answered 21/6, 2011 at 15:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.