Part 22 of this series of articles looked at the Model-View-Controller pattern and discussed how it is one way of structuring a user interface to avoid having too much code behind a screen.
This article will examine some of the shortcomings of Model-View-Controller, and describe an alternative, which is Model-View-Presenter.
Part 24 of this series of articles will then briefly examine some variations on the basic Model-View-Presenter pattern described here, and look at the advantages and disadvantages of the pattern.
Part 25 of this series of articles will look at the support that CAB/SCSF gives us for the Model-View-Presenter pattern.
There are a couple of user interface scenarios that are difficult to handle with the Model-View-Controller pattern. The first of these is the one that is most widely cited as a problem with Model-View-Controller, but in my opinion the second is the more difficult case to deal with, in spite of the fact that it’s hardly an unusual scenario:
1. Elements of our screen display depend on complex business logic
The canonical example here is coloring the background of a field in varying colors depending on the output from some business rule.
For example suppose we are showing daily sales figures for a business. We might want to color the background of a sales figure green if that figure is more than 10% above the average daily sales figure for the quarter, and color it red if it’s more than 15% below the average. Otherwise we leave the background white.
Model-View-Controller struggles with this scenario. Clearly it involves calculations involving business logic (averaging the sales figures for the quarter). In the Model-View-Controller pattern the business logic should go in the Model class. However, the only place we can sensibly put the coloring logic is in the View when it refreshes itself. We’ll come back to this below.
Note that we want to be able to enter the daily sales figure and have the background color change appropriately depending on the new value.
2. Elements of our screen display depend on what the user has selected in other screen components in a complex way
This could be as simple as a Save button being enabled only if the user has actually changed something on the screen (and being disabled again if the user changes the screen back to its original values).
Again the only place we can logically put this sort of logic in the Model-View-Controller pattern is in the View when it refreshes itself.
Whilst these problems are slightly different they can both be thought of as complex view logic surrounding the state of the user interface.
Why is Putting View Logic in the View a Problem?
In both of the examples above there probably isn’t all that much code relating to our view logic, and maybe putting it in the View in a Model-View-Controller pattern will be fine. However, with complicated screens this ‘view logic’ can run to many hundreds of lines of code. We don’t really want this code in our View, which we want to just be simple screen drawing code. Part of the idea of splitting out the View, after all, is that it becomes so simple we can easily replace it if we want to change our screen technology.
Another problem with having this logic in the View is that the event model may get quite complex. In my example it’s possible that a change in a sales figure that we’re not actually displaying could affect the background color of the textbox. Remember that we are comparing the textbox contents to the average daily sales. If the average daily sales change sufficiently we may need to raise an event to force a color change.
There’s another reason why developers prefer to get this ‘view logic’ out of the actual View class. It can be hard to automatically unit test a View class. Screen widgets often don’t lend themselves to unit testing. If the view logic is in another class it may be easier to unit test it.
Aside on Unit Testing in User Interfaces
I think the difficulties of unit testing user interfaces in Microsoft world are hugely exaggerated. Most Microsoft controls will let you do programmatically almost anything you can do with a mouse and keyboard. So, for example, we have a PerformClick method on a button, and settable SelectedIndex and SelectedItem properties on a ListBox. We can instantiate our screen in the test and interact with it programmatically in the same way we would if we were clicking on things. We have extensive unit tests that work this way in our current project.
It’s true that interactions between controls can be difficult to test (e.g. drag-drop operations). Also third-party (non-Microsoft) controls often don’t expose mouse and keyboard actions in the same way. However, in general you can usually unit test a user interface fairly extensively without recourse to restructuring your code as outlined in this article.
The Presenter in Model-View-Presenter
The first thing to understand about Model-View-Presenter is that it is very similar to Model-View-Controller, only with the Controller replaced with a Presenter (predictably).
The idea of the Presenter is that it can update the View directly. This isn’t permitted for a Controller in Model-View-Controller. This means we can put our complex ‘view logic’ described above into the Presenter and take it out of the View. Clearly we couldn’t do this with the Controller in Model-View-Controller since it had no easy way of updating the View with the results of the view logic: the View updated itself from the Model and the Controller was not involved.
Note that the Presenter, as with the Controller in Model-View-Controller, handles user events raised from the View as well. This means the View only contains screen drawing logic, which is what we want.
So a Presenter is able to ‘present’ data: it can directly update the View. On the other hand a Controller only controls: it takes user input and updates the Model as appropriate. Note that the Presenter is doing some controlling as well since it handles user events.
Diagram of Model-View-Presenter
Diagrammatically this looks as below:
As you can see, we again have three classes that interact. As with Model-View-Controller the Model class contains the data to be displayed, and the View class contains the code that actually draws the screen. We have already discussed the Presenter.
As with Model-View-Controller we can have multiple Presenter/View pairs of classes interacting with the same Model (with a change entered on one screen updating other screens showing the same data).
Class Interaction (active Model-View-Presenter with an active View)
When a user interacts with the View an event will be raised. This will be passed immediately to the Presenter (A). The Presenter will update the Model as appropriate (B): it may go back to the View to get the data it needs (F). The Model may at this stage raise an event that gets sunk in the View (C), leading to the View updating itself from the Model (D).
So far everything is the same as in active Model-View-Controller (except with the Controller replaced with the Presenter).
The difference is that when the Model is updated by the Presenter it may raise an event that also gets sunk back in the Presenter itself (E). The Presenter may then apply the complex view logic to work out what needs to be displayed before updating the View (F).
So in this version of Model-View-Presenter the View can update itself directly from the Model in simple cases where there is no view logic. When some view logic is needed the Presenter intervenes. It handles that logic and updates the View directly.
Interface on the View (F)
Another point to note here is that the Presenter accesses and updates the View through a clearly-defined interface on the View (F in the diagram). This has two effects. Firstly we can replace the View more easily with another screen technology since we know exactly what methods need to be exposed (those in the interface). Secondly this makes automated unit testing simpler. We can test the Presenter without needing screen elements directly by mocking the interface on the View in another class.
This article has described a basic Model-View-Presenter pattern and contrasted it with Model-View-Controller. It has examined why we need a different pattern to Model-View-Controller.
Part 24 of this series of articles will examine some variations on the Model-View-Presenter pattern described here, including the one in the Microsoft documentation for the SCSF. It will also discuss some of Martin Fowler’s user interface patterns that are relevant. References to articles for part 23 and part 24 will be given at the end of part 24.