Patterns: MVC, MVP and MVVM

In this article I would like to tell you what the difference between these patterns. Let’s start with the first main one – Model-View-Controller – it is a fundamental pattern that applies in the many technologies and every day makes easier life for programmers. If you ask software Architects about “How to implement this pattern”, I think you will get a couple of different answers and respectively a couple of solutions. Basically, there is one common thing in these patterns – is separation of User Interface (UI) from business logic, it allows do work for front-end developers not thinking about program code. If you remember school or university programming, it was a huge bunch of lines of code, written in code behind (for instance) of .aspx files, that’s not a good practice.

Model-View-Controller

MVC Schema

MVC has three key components: View (user interface), Model (business logic) and Controller (contains the logic that changes the model due to user actions, implements Use Case). The basic idea of this pattern is that the controller and view depends on model, but the model does not depend on these two components. It just allows you to develop and test a model without knowing anything about the views and controllers. Ideally, the controller also does not need to know about view (although in practice this is not always the case) and, ideally, one can switch controllers presentation, as well as the same controller can be used for different views (for example, the controller may depends on user who is logged in). The user sees a view, produces some action, this action redirects to the controller and subscribes for changes of the model, controller makes certain operations with data model, and the view gets the latest state of the model and displays it to the user.

Implementation in ASP.NET looks like as follows (example taken from MSDN [5]). Presentation – this is a common aspx markup:

<html>
<body>
    <form id="start" method="post" runat="server">
        <asp:dropdownlist id="recordingSelect" runat="server" />
        <asp:button runat="server" text="Submit" onclick="SubmitBtn_Click" />
        <asp:datagrid id="MyDataGrid" runat="server" enableviewstate="false" />
    </form>
</body>
</html>

Model – a separate class, which has methods for obtaining data (model implementations often includes Data Access Level):

public class DatabaseGateway
{
   public static DataSet GetRecordings()
   {
     DataSet ds = ...
     return ds;
   }
 
   public static DataSet GetTracks(string recordingId)
   {
      DataSet ds = ...
      return ds;
   }
}

Example of a model is not the best in this case, but it’s still not always need to have a really describe the business model in the classes, sometimes it’s enough to work with DataSets. The most interesting thing is the implementation of the controller, in fact it’s code behind of aspx page

using System;
using System.Data;
using System.Collections;
using System.Web.UI.WebControls;

public class Solution : System.Web.UI.Page
{
    private void Page_Load(object sender, System.EventArgs e)
    {
        if (!IsPostBack)
        {
            DataSet ds = DatabaseGateway.GetRecordings();
            recordingSelect.DataSource = ds;
            recordingSelect.DataTextField = "title";
            recordingSelect.DataValueField = "id";
            recordingSelect.DataBind();
        }
    }

    void SubmitBtn_Click(Object sender, EventArgs e)
    {
        DataSet ds = DatabaseGateway.GetTracks((string)recordingSelect.SelectedItem.Value);

        MyDataGrid.DataSource = ds;
        MyDataGrid.DataBind();
    }
    #region Web Form Designer generated code
    override protected void OnInit(EventArgs e)
    {
        //
        // CODEGEN: This call is required by the ASP.NET Web Form Designer.
        //
        InitializeComponent();
        base.OnInit(e);
    }

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.submit.Click += new System.EventHandler(this.SubmitBtn_Click);
        this.Load += new System.EventHandler(this.Page_Load);

    }
    #endregion
}

This approach will allow us to easily write tests for the model, but not for the controller (of course, all things are possible, but we need to try).

[TestFixture]
public class GatewayFixture
{
    [Test]
    public void Tracks1234Query()
    {

        DataSet ds = DatabaseGateway.GetTracks("1234");
        Assertion.AssertEquals(10, ds.Tables["Track"].Rows.Count);
    }

    [Test]
    public void Tracks2345Query()
    {
        DataSet ds = DatabaseGateway.GetTracks("2345");
        Assertion.AssertEquals(3, ds.Tables["Track"].Rows.Count);
    }

    [Test]
    public void Recordings()
    {
        DataSet ds = DatabaseGateway.GetRecordings();
        Assertion.AssertEquals(4, ds.Tables["Recording"].Rows.Count);

        DataTable recording = ds.Tables["Recording"];
        Assertion.AssertEquals(4, recording.Rows.Count);

        DataRow firstRow = recording.Rows[0];
        string title = (string)firstRow["title"];
        Assertion.AssertEquals("Up", title.Trim());
    }
}

Model-View-Presenter

MVP Schema

This pattern also consists from the three components. Looking at the diagram, it is clear that for representation is not necessary to subscribe for changes in the model, the controller is renamed as Presenter, lets representation know about changes. Current approach allows you to create an abstraction of representation. To implement this pattern, you need to create interfaces of representation. Each representation will have interfaces with a sets of methods and properties that are needed for presenter, presenter initializes with proper interface, subscribes for the events of representation and gives data when it needed. This approach allows you to develop applications using the methodology of TDD (Test-driven development). This pattern can also be applied to ASP.NET, let’s take a look at the previous example. Leave representation and model from the previous example, and code behind of the page we will change a little bit.

//Abstract View
public interface ISolutionView 
{
    string SelectedRecord { get; }
    DataSet Recordings { set; }
    DataSet Tracks { set; }
}
 
//Presenter
public class SolutionPresenter 
{
    private ISolutionView _view;
    
    public SolutionPresenter(ISolutionView view)
    {
        _view = view;
    }
    
    public void ShowTracks()
    {
        DataSet ds = DatabaseGateway.GetTracks(_view.SelectedRecord);
        _view.Tracks = ds;
    }
    
    public void Initialize()
    {
        DataSet ds = DatabaseGateway.GetRecordings();
        _view.Recordings = ds;
    }
}
 
 
//View
public class Solution : System.Web.UI.Page, ISolutionView
{
    private SolutionPresenter _presenter;
    
    private void Page_Load(object sender, System.EventArgs e)
    {
        if(!IsPostBack)
        {
            _presenter.Initialize();
        }
    }
 
    override protected void OnInit(EventArgs e)
    {
        base.OnInit(e);
        _presenter = new SolutionPresenter(this);
        submit.Click += delegate { _presenter.ShowTracks(); };
    }
 
    public string SelectedRecord 
    {
        get { return (string)recordingSelect.SelectedItem.Value; }
    }
    
    public DataSet Recordings
    {
        set 
        {
            recordingSelect.DataSource = value;
            recordingSelect.DataTextField = "title";
            recordingSelect.DataValueField = "id";
            recordingSelect.DataBind();
        }
    }
    
    public DataSet Tracks 
    {
        set 
        {
            MyDataGrid.DataSource = value;
            MyDataGrid.DataBind();
        }
    }
}

Right now we have logic in the presenter, and we are able to test SolutionPresenter with ISolutionView separately by using Mocks.

Model-View-ViewModel

Here again, there are three components: model, view, and a third component – an additional model called ViewModel. This pattern is suitable for technologies, where there is a two-way Binding (synchronization) of elements to the model, as in WPF. Difference between MVVM and MVP pattern is that for MVVM SelectedRecord property, from the last example, should be placed inside of the ViewModel, and it must be synchronized with the required field of view. So, this is the basic idea of ​​WPF. ViewModel – it’s kind of super converter that converts data of model to the representation, it describes the basic properties of the view and the logic of interaction with the model.

Useful links

  1. Model-View-Controller on MSDN
  2. Jean-Paul Boodhoo – Model View Presenter
  3. Josh Smith – WPF Apps With The Model-View-ViewModel Design Pattern
  4. Niraj Bhatt – MVC vs. MVP vs. MVVM
  5. Implementing Model-View-Controller in ASP.NET
  6. Model-View-Controller в .Net – Model-View-Presenter и сопутствующие паттерны (RUS)

P.S. I hope my article will give a basic vision in the understanding of patterns. I will be glad to see comments.

This work, “Patterns: MVC, MVP and MVVM”, is a derivative of “Паттерны: MVC, MVP и MVVM” by Denis Gladkikh, used under CC BY 4.0. “Patterns: MVC, MVP and MVVM” is licensed under CC BY 4.0 by Sergey Boiko.