Sunday, September 2, 2012

Using the MVP Pattern

I've mentioned in previous posts that I prefer the MVP pattern to MVC or MVVM. In truth, there are advantages and disadvantages in all the MV patterns (here's a quick explanation of the differences.) I prefer the MVP pattern mainly because it is simple to inplement and involves no binding magic. In this article, I'll describe the pattern and provide some guidence for how to use it that I have found helpful.

Description of the MVP Pattern

The Model View Presenter (MVP) pattern is a simple pattern. As you can see from the diagram below, the View and the Presenter reference each other, but only the Presenter references the Model:

The Model is your entity or domain object model. It contains the data and, in the case of a rich domain model, the domain behavior.

The View consists of Properties, mainly. Each control on the view that manipulates or displays data from the model will have one or more properties. These properties are exposed to the Presenter to allow it to interact with the View without knowing how the view is implemented. The View's properties may be base types, like string or decimal, or they may be more complex types, such as an IList. Although the View does not know the model, it may use the model types. It does, however, know the Presenter. This is because the View must call the methods of the Presenter whenever something occurs in the View. For example, the view might call a Load() method to get the Presenter to load data into the View, or Save() when a user clicks a "Save" button (or when some other circumstance dictates saving.)

The Pesenter does all the work. It has a reference to the View so that it can set or get the View's properties and it provides the methods that the View needs as I mentioned above. The Presenter is also responsible for maintaining the model, whether this is maintaining the model's state, interacting with a service or manipulating the model is some way, such as adding or removing objects from collections. The Presenter is similar to a code-behind except that it is abstracted behind an interface, thus allowing it to be easily unit tested.

View and Presenter Interaction

The View and Presenter are interdependant. Since the View depends on the Presenter to perform work on its behalf, it must have a reference to its Presenter. Likewise, the Presenter must have a reference to the View in order to get or set data. Because of this, there is most often a one-to-one relationship between Views and Presenters in an application.

The Presenter should be abstracted from the implementation of the View and visa-versa through interfaces. This is necessary in order to do good unit testing and to allow the Presenter to be used with Views that target different implementations. You might, for example, have the need to implement the same View as both an ASP.NET page and as a Windows Form. Because of the abstracted nature of the Presenter, the same Presenter is used for both, thus minimizing the coding effort.

Because of the possibility that the View may have different implementations, it is important that there be as little logic in the View as possible. Consider the following View definition:
 
public interface UserEditorViewInterface
{
   
UserEditorPresenterInterface Presenter { get; set; }

    string UserId { get; set; }
    string UserName { get; set; }

}
   

And the corresponding Presenter definition:

public interface UserEditorPresenterInterface
{
    UserEditorViewInterface View { get; set; }

    void Load(UserEditorViewInterface view);
    void Save();     
}
When implementing this view in a Windows Form, it might look like this:

public class UserEditor : Form, UserEditorViewInterface
{
    public UserEditorPresenterInterface Presenter { get; set; }

    public UserEditor()
    {
        this.Presenter.Load(this);
        this.saveButton.Click += (a,b) => {this.Presenter.Save();};
    }
    public string UserId
    {
        get { return this.userIdTextBox.Text; }
        set { this.userIdTextBox.Text = value; } 
    }
    public string UserName { get; set; }
    {
        get { return this.userNameTextBox.Text; }
        set { this.userNameTextBox.Text = value; }
    }
}


Notice how I implemented the two properties of the View in the form by simply reading and writing to the controls. I called the Load() method of the Presenter in the constructor (it could just as well be in the OnLoad() method of the form) and I also setup an anonymous delegate to handle clicking the "Save" button. In this way, I have condensed the code quite a bit.

Note: I like binding control events with anonymous delegates like this, but once you get more than a couple statements, it would be more readable to create a concrete delegate and reference a method.

The Presenter is just as straightfoward:

public class UserEditorPresenter : UserEditorPresenterInterface
{
    public UserEditorViewInterface View { get; set; }

   
    public void Load(UserEditorViewInterface view)
    {
       this.View = view;
       // do some load logic
    }
    public void Save()
    {
        UserInfo user = new UserInfo()
        {
            UserId = this.View.UserId,
            UserName = this.View.UserName
        };
        // save the object
    }
}

I left out the details about interacting with a service to retrieve and persist the UserInfo object, but there are a couple noteworth points in this implementation: First, I passed the View through the Load() method. I prefer to do this to be sure that the View is provided, but you could also set it using the property. Second, the domain object, UserInfo in this case, was recreated in the Save() method.

I often reconstruct the domain object in the Presenter simply because I cannot depend on the Presenter being stateful. Of course, if you were limiting it to an implementation where its reference would be maintained you could build it that way; but if it might be used in another implmenation, one that is stateless, then you cannot depend on it maintaining its own state. The simple solution, then, is to reconstruct the object.

An alternative to reconstructing the domain object is to use the View for state. For all practical purposes you are already doing this, but there may be more properties in the object than are exposed in the view. So, the View could hold a reference to the object. You would, however, depend on the View to handle state properly. That's not unreasonable, but it is possibly a point of failure.

Use of Interfaces and Factories in MVP

You may have noticed that both the View and the Presenter have interfaces. In fact, they reference each other through these interfaces. This is important for testing the presenter because it allows a unit test to create a mock-up of the view instead of referencing the actual view, which might not be possible. So, if the View does not reference the Presenter directly, how does it get the Presenter? An interface, after all, cannot be instantiated.

This is where factories come into play. Factories build objects. When implementing MVP, you should create a presenter factory. Such a factory will likely be very simple. Here is an example of a factory and its interface:

public interface PresenterFactoryInterface
{
    
ServiceFactoryInterface ServiceFactory { get; set; }

   UserEditorPresenterInterface CreateUserEditorPresenter(); 
}
public class PresenterFactory : PresenterFactoryInterface
{
   public ServiceFactoryInterface ServiceFactory { get; set; }
  public UserEditorPresenterInterface CreateUserEditorPresenter()
  {
       return new UserEditorPresenter()
      {
         Service = this.ServiceFactory.CreateService()
      };
  }

}
Note that I included the ServiceFactory. The factory for each layer would natually reference the factories for the next layer so that it may set dependency properties in the objects it creates. See my article on Factories for more details on how this works.

So where does the presenter factory get created? That will depend largely on the type of application you have. Here are some possibilities:
  • For Windows applications, the factory could be created when the application starts and stored in a static variable that is accessible throughout the application.
  • If the Application Controller pattern is used, you could create this factory in the controller, or created it on an as needed basis.
  • In Web applications, you might create the factory during the Application.OnStart event and store it in the Application state.
  • Also in web applications the factory might be created in a base class when a form in created (that could be costly, though, as it would occur on each post-back, but it might not be avoidable if the site is truly stateless.)
I find that creating the factory is an implementation detail best determined when designing the application. In all cases, there will be some code in a root level class that insantiates all concrete implementations of each factory. In the following example, each layer of factory is instantiated in the constructor of the consuming layer.

this.PresenterFactory = new PresenterFactory(
    new ServiceFactory(
       new DataAccessFactory()
    )
);

Instantiating the Presenter

Part of determining where to create the presenter factory depends on how you mean to create the presenter itself. That may very well depend on the platform you are using and the mechanism you have in place to instantiate views. For example, a Windows application may have the luxury of an Application Controller that can create a view and inject a presenter (I like that.) On the other hand, in an ASP.NET application, the web host controls creating the view; in that case, while injecting a dependency is possible, it is rather difficult.

Let's consider the first scenario. In the Application Controller pattern, a controller object determines which view to show the user. It is often responsible for creating that view, although that could be delegated. When it is responsbile for creating the view, it will have a reference to the presenter factory, thus allowing it to inject the presenter into the view, like so:

public void ShowUserManager()
{
    UserManagerViewInterface view = new UserManagerForm()
    {
        Presenter = this.PresenterFactory.CreateUserManagerPresenter()
    };
    // other implementation details
    ...
    view.Show();
    return view;
}

Other implementation details might include setting the View property of the presenter or calling a load method on the presenter or even setting MDI properties if that 's how the application works. So, in this case, all the factories would be created either in the Application Controller itself or in a startup method (like, static void Main()) when the Application Controller is created, which would mean the PresetnerFactory is injected into the controller.

This is fine for a Windows or WPF application, but an ASP.NET application cannot call a "Show" method on the view, so the controller cannot be so direct. The simplest approach is to put the presenter factory in an Application state variable and create the presenter in the Page_Load() method:
       
protected void Page_Load(object sender, EventArgs e)

{
     this.Presenter = ((ApplicationController)Application["Controller"])
             .PresenterFactory.CreateUserManagerPresenter()
}


No comments:

Post a Comment