Note: This post is part of a series. You can find the introduction and overview of the series here.
Just a little warning up front: I'm not going to show a diagram of the architecture. When it comes to this kind of posts, people often just scroll until they see a diagram which depicts the architecture, glance over it, either think they get it or won't get it, and base their opinions on just that. I want people to actually focus and read what i'm saying about this, so i'm not using any diagrams. This approach usually results in increased understanding of the architecture and less misunderstandings. Obviously, it's not a foolproof approach as you'll likely soon discover in the comments.
The MVP (Model-View-Presenter) pattern is an MVC-derivative pattern. The Presenter part is often referred to as a controller and its responsibilities differ between the two most known variants (more on that in just a little bit) of MVP. But the presenter is actually very comparable to the Controller in MVC. The biggest difference, in my opinion, between MVP and MVC is the following: In MVC, every user-initiated action is handled directly by the controller. In MVP, every user-initiated action is handled by the View, who then delegates this to the Presenter (or Controller in many implementations). That's why you often see MVC being used in web applications (where most MVC frameworks turn a click of a button into a direct method call on a Controller) and MVP in rich clients (where a button's Click event handler calls a method on the Presenter/Controller).
As if the difference between MVC and MVP weren't small enough, MVP is actually split up in 2 variants to add more confusion to the whole. One of them is the Passive View, and the other is the Supervising Controller. Simply put, in the Passive View variant the View is only responsible for visualizing data and delegating user input to the presenter. All logic that is required to control the View (including View-update behavior) and interact with the Model is put in the Presenter/Controller. In the Supervising Controller variant, the View is responsible for visualizing data, delegating user input, as well as View-update behavior. That means that the View will update itself when data is given to it, instead of having the Presenter/Controller take care of that. If you haven't made the link yet, the location of that View-update behavior of the Supervising Controller variant of MVP fits perfectly with Silverlight/WPF's data binding features (more on that later).
Now, i can imagine that the first 3 paragraphs of this post were pretty confusing with all these details about these patterns and their variations. But hey, blame Martin Fowler for that one. I'd like to avoid any future confusion with regards to this approach so i want to go over each part of this client-side architecture to make sure that you fully know what each part is responsible for.
In most (if not all) Silverlight applications, the Model will actually be a Service Layer that is hosted on an application server. Behind this Service Layer, you'll find either a rich Domain Model with behavior, or some representation of your Data Model and some other way to access the functionality that you need from your client. In the case of WPF applications, your Model is either a service layer as well, or it might actually be used directly in the case of a fat client. Whether it's behind a Service Layer or not, the Model contains and exposes (some of) the actual business logic of your system/application.
The View is responsible for visualizing the data that it needs to show, and to capture user-initiated actions (both in the form of data modification as well as clicks on user controls or other typical UI actions) so they can be delegated to the Presenter. That's all it should do. It makes use of data binding capabilities where it makes sense, and the only logic that it contains is to delegate user-initiated actions to the presenter, or to do something view-specific which can't be done through data binding (for instance: selecting the correct item in a TreeView). I know many MVVM evangelists advocate no code at all in the View's code behind, but there is a limit to how much logic you can pull out of the View while still providing more benefits than drawbacks. Initiating actions on the Presenter and interacting with actual UserControls is something that you can safely leave in the View, since pulling that kind of stuff out of the View hardly ever introduces actual benefits and is more often done to serve purely theoretical benefits, and it's just not worth the trouble.
The Presenter is basically the coordinator between the user, the View and the Model. Before the user can initiate an action or modify data, it needs to see either that data and/or a UserControl which could trigger that action. As mentioned earlier, visualizing data or UserControls is the responsibility of the View. The Presenter needs to retrieve that data from the model before it can be shown in the View, and it can also decide which actions can or can not be executed by the user (according to the user's permissions for instance, or according to the context of the current workflow, or a combination of both). When a user initiates an action (for instance, persisting modified data in the View), the Presenter needs to interact with the Model to complete the User's requested action.
At this point, you might be wondering: what exactly is the big difference between the Presenter and the ViewModel in the MVVM approach? Well, the answer to that is an extra part which i haven't talked about in this post yet. As i'm sure you all know, the ViewModel in the MVVM approach also takes care of everything that is needed to make good use of data binding. Silverlight and WPF have some very strong data binding capabilities and you'd be a fool not to use them. I know there are quite a few people who dislike data binding (especially when it's string-based) but in this case, the benefits definitely outweigh the drawbacks, by a very large margin even. So whichever client-side architecture you choose to use, it would be wise to make sure that it supports Silverlight/WPF's data binding features to the fullest. In fact, i suppose that's one of the biggest reasons why the MVVM pattern has taken off the way it did. It fully supports and encourages using the data binding features.
But, as we all know, with great power comes great responsibility. Data binding makes a lot of stuff easy to do. It removes a lot of repetitive, error-prone code that we'd either write manually every single time, or have generated by some tool/plugin. But if you use it incorrectly, data binding might cause unexpected method calls or accessing of properties. In the worst cases, this could result in unnecessary expensive operations being performed without you realizing it (at first). And i don't think i'm going out on a limb here by claiming that quite a few people have gotten bitten by this, no matter how good or bad you are as a developer.
From a performance point of view, you ideally want to make optimal use of Silverlight/WPF's data binding features, without risking unexpected expensive operations. From a code quality and design point of view, you might agree with me that facilitating data binding is a responsibility that should be shouldered by a dedicated class. With that, i mean a class which only takes care of everything that is related to data binding. And that is the part of this architecture i haven't discussed yet: the BindingModel (which i used to refer to as some slimmed down version of a PresentationModel, but that only caused more confusion).
The BindingModel is a class which is used by both the Presenter and the View. The Presenter puts data from the Model in the BindingModel. The View in turn binds to the BindingModel. If a user modifies that data, those modifications are immediately applied in the BindingModel because of Silverlight/WPF's two-way binding. If required/wanted/preferred, the BindingModel can perform simple client-side validation to the modified data. If the user then initiates an action, the Presenter will use the data in the BindingModel to interact with the Model. The BindingModel however will never interact with the Model directly.
And that is the big difference between this MVP approach and the MVVM approach. Data binding and interacting with the model are strictly separated, which makes sense on multiple levels. For one, this approach results in a better Separation Of Concerns (interaction with the model vs facilitating data binding). But it also makes sure that unexpected data binding events can never lead to unexpected expensive and unwanted interaction with the Model.
In the next post, we'll go over the infrastructure bits you'll need to work with this approach.
Pingback: WPF Related Links « QuantuMatrix’s Weblog