Those who know me know that I have a passion for software architecture
and after developing projects using Model-View-ViewModel (MVVM),
Model-View-Presenter (MVP), and Model-View-Controller (MVC), I finally
feel qualified to talk about the differences between these
architectures. The goal of this article is to clearly explain the
differences between these 3 architectures.
First, the let’s define common elements. All 3 of the architectures are designed to separate the view from the model.
Model
- Domain entities & functionality
- Knows only about itself and not about views, controllers, etc.
- For some projects, it is simply a database and a simple DAO
- For some projects, it could be a database/file system, a set of
entities, and a number of classes/libraries that provide additional
logic to the entities (such as performing calculations, managing state,
etc)
Implementation: Create classes that
describe your domain and handle functionality. You probably should end
up with a set of domain objects and a set of classes that manipulate
those objects.
View
- Code that handles the display
- Note that view related code in the codebehind is allowed (see final notes at the bottom for details)
Implementation: HTML, WPF, WindowsForms, views created programmatically – basically code that deals with display only.
Differences between Presenters, ViewModels and Controllers
This is the tricky part. Some things that Controllers, Presenters, and ViewModels have in common are:
- Thin layers
- They communicate with the model and the view
The features of each.
Presenter (Example: WinForms)
- 2 way communication with the view
- View Communication: The view communicates with the presenter by
directly calling functions on an instance of the presenter. The
presenter communicates with the view by talking to an
interface implemented by the view.
- There is a single presenter for each view
Implementation:
- Every view’s codebehind implements some sort of IView interface.
This interface has functions like displayErrorMessage(message:String),
showCustomers(customers:IList<Customer>), etc. When a function
like showCustomers is called in the view, the appropriate items passed
are added to the display. The presenter corresponding to the view has a
reference to this interface which is passed via the constructor.
- In the view’s codebehind, an instance of the presenter is
referenced. It may be instantiated in the code behind or somewhere
else. Events are forwarded to the presenter through the codebehind.
The view never passes view related code (such as controls, control
event objects, etc) to the presenter.
A code example is shown below.
//the view interface that the presenter interacts with
public interface IUserView
{
void ShowUser(User user);
...
}
//the view code behind
public partial class UserForm : Form, IUserView
{
UserPresenter _presenter;
public UserForm()
{
_presenter = new UserPresenter(this);
InitializeComponent();
}
private void SaveUser_Click(object sender, EventArgs e)
{
//get user from form elements
User user = ...;
_presenter.SaveUser(user);
}
...
}
public class UserPresenter
{
IUserView _view;
public UserPresenter(IUserView view){
_view = view;
}
public void SaveUser(User user)
{
...
}
...
}
ViewModel (Example: WPF, Knockoutjs)
- 2 way communication with the view
- The ViewModel represents the view. This means that fields in a view
model usually match up more closely with the view than with the model.
- View Communication: There is no IView reference in the ViewModel.
Instead, the view binds directly to the ViewModel. Because of the
binding, changes in the view are automatically reflected in the
ViewModel and changes in the ViewModel are automatically reflected in
the view.
- There is a single ViewModel for each view
Implementation:
- The view’s datacontext is set to the ViewModel. The controls in the view are bound to various members of the ViewModel.
- Exposed ViewModel proproperties implement some sort of observable
interface that can be used to automatically update the view (With WPF
this is INotifyPropertyChanged; with knockoutjs this is done with the
functions ko.observable() and ko.observrableCollection())
Controller (Example: ASP.NET MVC Website)
- The controller determines which view is displayed
- Events in the view trigger actions that the controller can use to modify the model or choose the next view.
- There could be multiple views for each controller
- View Communication:
- The controller has a method that determines which view gets displayed
- The view sends input events to the controller via a callback or
registered handler. In the case of a website, the view sends events to
the controller via a url that gets routed to the appropriate controller
and controller method.
- The view receives updates directly from the model without having to go through the controller.
- Note: In practice, I don’t think this particular feature of MVC is
employed as often today as it was in the past. Today, I think
developers are opting for MVVM (or MVP) over MVC in most situations
where this feature of MVC would have been used. Websites are a
situation where I think MVC is still a very practical solution.
However, the view is always disconnected from the server model and can
only receive updates with a request that gets routed through the
controller. The view is not able to receive updates directly from the
model.
Implementation (for web):
- A class is required to interpret incoming requests and direct them
to the appropriate controller. This can be done by just parsing the
url. Asp.net MVC does it for you.
- If required, the controller updates the model based on the request.
- If required, the controller chooses the next view based on the
request. This means the controller needs to have access to some class
that can be used to display the appropriate view. Asp.net MVC provides a
function to do this that is available in all controllers. You just
need to pass the appropriate view name and data model.
MVVM and MVP implementation seem pretty
straightforward but MVC can be a little confusing. The diagram below
from Microsoft’s Smart Client Factory documentation does a great job at
showing MVC communication. Note that the controller chooses the view
(ASP.NET MVC) which is not shown in this diagram. MVVM interactions
will look identical to MVP (replace Presenter with ViewModel). The
difference is that with MVP, those interactions are handled
programmatically while with MVVM, they will be handled automatically by
the data bindings.
General rules for when to use which?
MVP
- Use in situations where binding via a datacontext is not possible.
- Windows Forms is a perfect example of this. In order
to separate the view from the model, a presenter is needed. Since the
view cannot directly bind to the presenter, information must be passed
to it view an interface (IView).
MVVM
- Use in situations where binding via a datacontext is possible. Why?
The various IView interfaces for each view are removed which means
less code to maintain.
- Some examples where MVVM is possible include WPF and javascript projects using Knockout.
MVC
- Use in situations where the connection between the view and the rest
of the program is not always available (and you can’t effectively
employ MVVM or MVP).
- This clearly describes the situation where a web API is separated
from the data sent to the client browsers. Microsoft’s ASP.NET MVC is a
great tool for managing such situations and provides a very clear MVC
framework.
Final notes
- Don’t get stuck on semantics. Many times, one of your systems will
not be purely MVP or MVVM or MVC. Don’t worry about it. Your goal is
not to make an MVP, MVVM, or MVC system. Your goal is to separate the
view, the model, and the logic that governs both of them. It doesn’t
matter if your view binds to your ‘Presenter’, or if you have a pure
Presenter mixed in with a bunch of ViewModels. The goal of a
maintainable project is still achieved.
- Some evangelists will say that your ViewModels (and Presenters) must
not make your model entities directly available for binding to the
view. There are definitely situations where this is a bad thing.
However, don’t avoid this for the sake of avoiding it. Otherwise, you
will have to constantly be copying data between your model and
ViewModel. Usually this is a pointless waste of time that results in
much more code to maintain.
- In line with the last point, if using WPF it makes sense
to implement INotifyPropertyChanged in your model entities. Yes, this
does break POCO but when considering that INotifyPropertyChanged adds a
lot of functionality with very little maintenance overhead , it is an
easy decision to make.
- Don’t worry about “bending the rules” a bit so long as the main goal of a maintainable program is achieved
- Views
- When there is markup available for creating views (Xaml, HTML, etc),
some evangelists may try to convince developers that views must be
written entirely in markup with no code behind. However, there are
perfectly acceptable reasons to use the code behind in a view if it is
dealing with view related logic. In fact, it is the ideal way to keep
view code out of your controllers, view models, and presenters.
Examples of situations where you might use the code behind include:
- Formatting a display field
- Showing only certain details depending on state
- Managing view animations
- Examples of code that should not be in the view
- Sending an entity to the database to be saved
- Business logic
Happy coding.