Blog Moved to http://podwysocki.codebetter.com/

Blog Moved to http://podwysocki.codebetter.com/
posts - 277 , comments - 156 , trackbacks - 27

Grokking the Model View Presenter (MVP) Variations

For many of my current ASP.NET projects, I've been using the Model View Presenter (MVP) for this.  However, there are many ways to implement this and if you ask someone, you'll likely get a differing opinion each and every time.  Such as the case with the Model View Presenter.  I've covered this before, but in the context of SharePoint, so now I'm just going to stick with ASP.NET and the concepts itself.

The Model View Presenter

Martin Fowler came up with the concept for the Model View Presenter back in 2004.  The Model View Presenter is a slight variation of the Model View Controller that we've heard so much about with such frameworks as ASP.NET MVC, MonoRail, Struts and of course Ruby on Rails.  The basic idea is that the model stores the data, the view shows a representation of the model, and the presenter handles the interaction between the two.  The main reason for the use of this framework is that you can use the existing ASP.NET infrastructure to support this without any additional libraries unlike ASP.NET MVC and MonoRail.

The key benefits of course is testability and separation of concerns.  The view is basically dumb and does nothing but what the presenter tells it to do.  This allows for easy testing with mock views or test doubles.  Now questions arise when you start handling events in these presenters.   Billy McAfferty has a good writeup on the subject which is still a great reference.

But since then, Martin Fowler split the Model View Presenter into two, the Passive View and the Supervising Controller (Presenter).

The Passive View

The intent of the Passive View is that it is a rather dumb view.  This means the majority of the code used for setting up the view and all the logic is moved into the presenter.  The view is just a thin wrapper around the presenter with no behaviors defined.  Basically, it just defines the contract of the data to display, and no real concept of what the model is.  Jeremy Miller has a great writeup of this in his series "Build Your Own Cab" with Part #4 covering the Passive View.

So, to put it succinctly, the main points of the Passive View are:
  • The view should not know about the model
  • The view should be simple as possible
  • The view should implement an interface so you can mock it
  • If the view needs to use a complex type, then use an adapter to break it down

Below is a basic example of a search screen for a given employee to return employee information for the given employee ID.

public interface IEmployeeSearchView
{
     string EmployeeId { get; }

     string FirstName { set; }

     string Lastname { set; }

     int Level { set; }
}

And then we can define the presenter with just a stub so that we can test our interaction.  Note that our model is defined through the IEmployeeTasks interface and I'm not really going to cover what that does.

public class EmployeeSearchPresenter
{
     private IEmployeeTasks tasks;
     private IEmployeeSearchView view;

     public EmployeeSearchPresenter(IEmployeeSearchView view, IEmployeeTasks tasks)
     {
          this.view = view;
          this.tasks = tasks;
     }

     public void InitializeView()
     {
          Employee employee = tasks.GetEmployee(view.EmployeeId);
          view.FirstName = employee.GivenName;
          view.Lastname = employee.Surname;
          view.Level = employee.Rank;
     }
}

Well, if we were truly doing TDD, we would have just left InitializeView to do nothing, then made it fail, then put in the code to make it pass, but that's a bit much for a blog post and more for a webcast and so on.  As you can note from our presenter, it has no idea about events or when it gets invoked.  In other words, the presenter gets invoked at certain times during the page such as an Click event. 

Now, I'm not happy with the above code, because I'm setting the Employee object and doing that mapping of the view from the employee object and it just has a code smell to it.  So, where can we move that logic?  How about into the view itself?  Let's modify the view to include more things.

public interface IEmployeeSearchView
{
     // Same as above plus this
     void SetEmployee(Employee employee);
}

Now, this makes the view have some logic in it, or does it?  We'll use an adapter approach to fix that.

public static class EmployeeAdapter
{
     public static void SetEmployee(IEmployeeSearchView view, Employee employee)
     {
          view.FirstName = employee.GivenName;
          view.LastName = employee.Surname;
          view.Level = employee.Rank;
     }
}

Now, the implementing view must do this for the SetEmployee method.

public void SetEmployee(Employee employee)
{
     EmployeeAdapter.SetEmployee(this, employee);
}

And in turn, we modify our InitializeView method to incorporate this change as well:

public void InitializeView()
{
     Employee employee = tasks.GetEmployee(view.EmployeeId);
     view.SetEmployee(employee);
}

So, as you can see, it's made our mapper code a bit more clearer and it's a better approach when tackling the Passive View. 

Now, let's move onto the Supervising Controller.

Supervising Controller

Now in more complicated scenarios where you need to handle events, that's where the Supervising Controller comes into play.  Both Phil Haack and Jeremy Miller have great writeups on this.  Phil's approach uses the ASP.NET Event Model to control this through defining a base view that can be applicable to all views and then implementing a custom view on top of this.

public interface IView
{
     event EventHandler Init;

     event EventHandler Load;

     bool IsPostBack { get; }

     void DataBind();

     bool IsValid { get;}
}

public class IEmployeeEditView : IView
{
     string EmployeeId { get; }

     string FirstName { get; set; }

     string LastName { get; set; }

     int Level { get; set; }

     event EventHandler EmployeeSaved;
}

So, as you can see, the real differences start to emerge when you start handling the events and such and you subscribe through the presenter itself.  We'' stub out what the presenter will look like.

public class EmployeeEditPresenter
{
     private IEmployeeEditView view;
     private IEmployeeTasks tasks;

     public EmployeeEditPresenter(IEmployeeEditView view, IEmployeeTasks tasks)
     {
          this.view = view;
          this.tasks = tasks;
          SubscribeToEvents();
     }

     private void SubscribeToEvents()
     {
          view.EmployeeSaved += OnEmployeeSaved;
     }

     private void OnEmployeeSaved(object sender, EventArgs e)
     {
          Employee employee = new Employee(view.EmployeeId);
          employee.GivenName = view.FirstName;
          employee.Surname = view.LastName;
          employee.Rank = view.Level;
          tasks.SaveEmployee(employee);
         DataBind();
     }

     // More code here
}

Once again, I went ahead and wrote the code before the tests because once again, this is a blog post and not a web cast.  Anyhow, so we've seen two basic ways of defining your views and presenters.

Variations on the Theme

So, basically we have two ways of attacking the problem:
  1. Expose events off the view to which the presenter can subscribe.  This of course ties it to the event model as defined in ASP.NET or your UI of choice.  This is using the Supervising Controller approach.
  2. Have the presenter methods called within the events in your UI as noted in the Passive View approach.
Some might object to the Supervising Controller approach as it ties you to the ASP.NET event model.  They criticize this approach because they may want to substitute a Web UI with a Windows Forms application, with a WPF application, etc.  But, how realistic is that scenario where you want both options for a UI to use the same logic and so on?

Let's take another approach as well.  Jim Bolla posted about what he calls the Observable View Pattern.  This uses the observer pattern and it very much like the Passive View but with events on the view.  Let's walk through a simple example:

Note that we're using the IView interface from above.

public class IEmployeeEditView : IView
{
     string EmployeeId { get; }

     string FirstName { get; set; }

     string LastName { get; set; }

     int Level { get; set; }

     event EventHandler EmployeeSaved;
}

Now, let's see what the page might look like.

public class EditEmployee : Page, IEmployeeEditView
{
       protected void OnSaveButtonClick(object sender, EventArgs e)
       {
           if (EmployeeSaved != null)
               EmployeeSaved(this, EventArgs.Empty);
       }

      protected override void OnInit(EventArgs e)
      {
           new EditEmployeeViewObserver().Observe(this);
 
           if (Init != null)
               Init (this, EventArgs.Empty);
      }
}

And in turn, our EditEmployeeViewObserver would look like this:

public class EditEmployeeViewObserver
{
       public void Observe(IEmployeeEditView view)
       {
           view.Init += delegate
           {
               new EditEmployeeViewInitializationProcess(view).Execute();
           };
 
           view.EmployeeSaved += delegate
           {
                new EditEmployeeSavedProcess(view).Execute();
           };
       }
}

The key to this approach is using events.  This has the view creating the observer and then forgetting about it after the Observe method.  It shouldn't fall out of scope during the setup here after that.  The observer then forwards to the process class which in turn implements the Command pattern.  It's a pretty interesting approach I must say.


Conclusion

So, the question then arises, which to use and when?  Well, Martin Fowler gives the answers in his links from above, but it's down to personal preference.  I've followed more of Phil Haack's approach to the Supervising Controller.  Mostly the view doesn't do anything, as the presenter subscribes to the view's events.  Jeremy Miller thinks a different way as well as noted here.  But, at the end of the day it's down to preference.  Each approach works and has its pluses and minuses. 

kick it on DotNetKicks.com

Print | posted on Wednesday, January 23, 2008 12:38 AM | Filed Under [ ASP.NET Test Driven Development ]

Feedback

Gravatar

# re: Grokking the Model View Presenter (MVP) Variations

Nice writeup and thanks for the link love Matthew. The MVP pattern actually goes back quite a bit farther. Fowler popularized it after the Humble Dialog Box paper, but the pattern name goes back to some Smalltalkers in the early 90's. All roads seem to lead back to Smalltalk.

"Some might object to the Supervising Controller approach as it ties you to the ASP.NET event model."

I wouldn't count on any kind of MVP usage enabling you to go unchanged from WebForms to WinForms without some change to the Presenter. Just like switching database engines with an ORM, it only minimizes the differences.
1/23/2008 7:53 AM | Jeremy D. Miller
Gravatar

# re: Grokking the Model View Presenter (MVP) Variations

True, I should have read that a bit more carefully. And yes, as with most great things in software today, it leads back to SmallTalk as most people would say. Just ask Eric Evans...

Well, I was responding to the DNR show on the MVP as talked about multiple times on there. They seemed to indicate that you can make your MVP completely agnostic and I don't think that's going to happen without completely tying your hands doing so. But, yes, this pattern does keep that kind of change to a minimum to switch between your models as that's pretty abstracted anyways, but your presenter and your view, that's another matter.
1/23/2008 12:30 PM | Matthew Podwysocki
Gravatar

# re: Grokking the Model View Presenter (MVP) Variations

I’m impressed, I must say. Very rarely do I come across a blog that’s both informative and entertaining, and let me tell you, you’ve hit the nail on the head. Your blog is important; the issue is something that not enough people are talking intelligently about. I’m really happy that I stumbled across this in my search for something relating to this issue
11/26/2010 1:43 AM | toronto escorts
Post A Comment
Title:
Name:
Email:
Comment:
Verification:
 
 

Powered by: