How to think about MVC, MVP, and MVVM?

Datetime:2016-08-23 01:25:08          Topic: MVVM Model           Share

This article is about my personal explanation of the reputed design patterns: Model-View-Controller, Model-View-Presenter, and Model-View-ViewModel; followed by several judgement, and a discussion for the applying of those patterns to the Web.

Let’s start with Model.

Model: the core of an application

At the core of an application is a place so-called Model where business objects and use-case objects live. Normally the outside world interacts to the Model by sending input to use-case objects, these objects then manipulate business objects and finally return output back to the outside world.

That outside world implies a new component, we name it as UI (User Interface) or View.

User interaction: the born of View

A View has two roles (and should not more than two):

  1. Input sender: to send input to the Model.
  2. Output displayer: to display output notified from the Model.

In order to do the role #1, the View needs a reference to the Model. In other words, the View needs to depend on the Model:

The role #2 suggests that the Model would depend on the View:

This is terrible! The Model should not know directly about the View. We can turn this direct dependency into an indirect one by using Dependency Inversion (note that the indirect dependency will be denoted as a dashed arrow):

Or we can use a more specific version of Dependency Inversion so-called Observer Pattern :

It seems to be good enough! However, in reality, there’s often a format mismatch between the input sent from the View and the input accepted by the Model. Thus, we need an input converting. Who will do this task?

The Model? No, the Model must not have any knowledge about View (the input format sent from View).

The View? Still no, as it causes two problems:

  • The View are doing too many tasks.
  • It’s impossible to reuse the converting to another View.

It’s time to introduce a new component: Controller.

MVC: a Controller is an input converter and forwarder

The idea of MVC is described clearly in the diagram above. The View sends input to the Controller; the Controller then converts the input into a suitable format accepted by Model, and forwards the formatted input to Model; next, the Model handles the input and finally notifies output to the View.

There could be 3 design patterns applicable in MVC: a View can be a Composition of multiple smaller Views, a View can swap the Controller to change its Strategy , and – as we have known – a View can be an Observer of a Model.

Please note that the initial View and the final View are not necessary the same. They might be two different Views:

This case is rare but it’s worth to aware. Actually, in classic definition of MVC, the initial View is not mentioned, only the final one is discussed. I think the root author of MVC didn’t consider a View as an input sender, he may consider a View is merely for viewing – an output displayer. Nevertheless, I find that mentioning the initial View would be clearer and easier to understand the pattern.

MVC pattern still has a drawback: the indirect dependency between the Model and the View. This dependency leads to two issues:

  • The Model has one more relationship for notifying the output.
  • The View has one more task of converting the output format (again, there’s also a mismatch between the format of the output notified by the Model and the data understood by the View).

Remember, we introduced this dependency before the appearance of the Controller. No we have the Controller, we can leverage it to break the dependency between the Model and the View. This is the content of the MVP pattern.

MVP: a Presenter is a Controller plus an output converter and forwarder

The dependency was broken nicely. Now the Controller – not the Model – is the one who notifies output to the View, thus the Controller is able to do the output converting task without any problem. In this manner, the Controller looks like a presenter who presents ready data to the View, so it could be renamed to Presenter.

How about the output transferring from the Model to the Presenter? It can be done by active calls invoked from the Presenter to the Model (as in the diagram above). Alternatively, in case you’re happy with one more relationship of the Model and fall in love with Dependency Inversion / Observer Pattern, you can still let the Model notifies output to the Presenter:

In any case, the Presenter always includes the tasks of a Controller plus the new tasks. Do you see it is bulky? If your answer is yes, you may want to consider the MVCP pattern.

MVCP: why not both Controller and Presenter?

Nothing special to this pattern except that it extracts the Controller from a bulky Presenter. In this pattern, the Presenter is really a pure Presenter as it doesn’t do the tasks of a Controller anymore.

This pattern is not mine (but the name is), it was introduced by Uncle Bob in his workshop Architecture – The Lost Years :

MVVM: a ViewModel is a degenerated Presenter looking like a model of the View

Now let’s focus on how the Presenter sends ready output to the View. If Dependency Inversion was used, it would cause a bunch of setter methods on the View, and the same number calling those methods in the Presenter. If Observer Pattern was used, it would cause a bunch of getter methods on the Presenter, and the same number of calling those methods in the View.

In both of the two cases, we have to write a lot of code just to sync the ready output from Presenter to the View. Hence it would be better if we have an automatic data binding mechanism. In such a mechanism, of course, there would be two sides of data model to be sync: one is the data model of the View, one is the ready output being held and exposed by the Presenter. The fact that the Presenter exposes a data model identical with the View’s data model makes it look like a ViewModel.

If that data binding mechanism is adopted, why don’t we also use it for the sync from the Model to the Presenter? If we take advantage of the data binding mechanism, then we have the MVVM pattern:

In this way, the only code we need to write for the Presenter – now is named as ViewModel – is the converting code.

Judgement: Dependency Inversion vs Observer Pattern

As we can see in the diagrams describing Dependency Inversion and Observer Pattern, the advantage of Dependency Inversion is that the View does not need to depend on the Model. However, this technique introduces one more particular interface every time it is applied. For instance, when we apply it for another View & Model, we would need a new different interface.

Observer Pattern, on the other hands, uses stable interface (Observer) and class (Subject) which are even existed in Java standard libraries. Of course, the clear disadvantage of this pattern is the dependency of the View upon on the Model.

Judgement: MVC vs MVP vs MVCP vs MVVM

Deciding whether to use MVC or MVP or MVCP is quite a hard trade-offs. It depends on how you distribute and balance tasks to your components. If a Controller is fat, it should not become a Presenter in MVP. If a View is complex, it should not take the additional task of output converting as in MVC. If a Presenter is big, it should be divided as in MVCP. However, after all, the evaluation of fat/complex/big is really an art and is subtle. Because of this difficulty, sometimes your decision may be mainly driven by your habit.

To adopt MVVM, first, you should have a good reason to use MVP as discussed, and next, more important, your technology must support a data binding mechanism, otherwise the process of manual binding would discourage you. Sometimes the data binding mechanism is so attractive that it may dominate every judgement.

How about the Web?

The Web is a delivery mechanism. Our components (M, V, C, P, VM) are located in different computers and communicate through the HTTP protocol. Views usually run on clients whereas the rest of components run on servers.

The special thing of the Web is that output sent from servers to Views (on clients) are often complicated and in various formats. In cases of using AJAX, an output could be a plain text, or a complex JSON string … In typical cases, it is a whole web page represented in HTML/JavaScript/CSS code with images, sounds …

Because of this complication, we would need a new component – named as ViewOutput – which is responsible for constructing final output to be sent to Views. A ViewOutput augments output returned by Model/Presenter/ViewModel with web stuff such as HTML code, JSON string … and then sends the final output to the View through an HTTP response. Who would be responsible for creating the right ViewOutput and controlling it? Clearly, the answer is Controller/Presenter/ViewModel.

Hence, the MVC pattern applied for the Web should look like this:

Similar for the MVP and MVVM patterns.

Conclusion

All the MV* design patterns discussed in this article are usually applied in large software which have the participation of UI. Although each pattern has a slight difference: MVC accepts the indirect dependency between the Model and the View, MVP breaks this dependency by making the Controller become a Presenter, MVVM degenerates the Presenter to a model of the View; all of them are for only one purpose: separation of concerns . A Controller converts input and should be THIN, a Model handles business logic and should be SMART, a View displays output and should be DUMB. Separation of concerns, in my opinion, is the most valuable principle of software design.





About List