30

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?

ardila
  • 1,237
  • 1
  • 12
  • 23
Tower
  • 87,855
  • 117
  • 329
  • 496

5 Answers5

48

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.

ardila
  • 1,237
  • 1
  • 12
  • 23
Marijn
  • 9,846
  • 4
  • 52
  • 75
  • I'd like to add some examples, but I'm not that good at Javascript, sorry, – Marijn Jun 21 '11 at 19:59
  • 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? – Tower Jun 22 '11 at 12:13
  • Yesterday I did a quick [google search](http://www.google.nl/search?q=javascript+mvp). I found [this SO question](http://stackoverflow.com/questions/1102215/mvp-pattern-with-javascript-framework) interesting to read. – Marijn Jun 22 '11 at 12:17
  • 2
    Besides the links in my answer, I found the [build-your-own-cab-series](http://codebetter.com/jeremymiller/2007/07/26/the-build-your-own-cab-series-table-of-contents/) great in explaining the different flavors of MVP. It's specific to .NET though. – Marijn Jun 22 '11 at 12:21
  • 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. – Marijn Jun 22 '11 at 18:52
  • 1
    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. – Tower Jun 23 '11 at 11:54
  • 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! – Marijn Jun 23 '11 at 12:28
  • Many view-presenter combinations can be created as singletons by your dependency injection framework. Others pairs should be created by your event bus. – HDave Feb 03 '12 at 15:19
  • See http://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. – Paul Zahra Mar 27 '13 at 09:17
  • 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. – Paul Zahra Mar 27 '13 at 09:48
  • [sp - "supervising conroller"] – jnm2 Apr 29 '14 at 13:00
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.

ardila
  • 1,237
  • 1
  • 12
  • 23
Neil McGuigan
  • 41,314
  • 10
  • 106
  • 137
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.

dario_ramos
  • 6,536
  • 7
  • 50
  • 104
  • 3
    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. – Marijn Jun 21 '11 at 20:02
  • 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. – Marijn Jun 21 '11 at 20:04
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;
  }
}
Ciaran
  • 531
  • 2
  • 11
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.

Ciaran
  • 531
  • 2
  • 11