Wikipedia is not a technical manual
There are lots of confusion with the Wikipedia's MVC image. The issue is that in UML class diagrams A -> B
means that A is active and calls B (and thus A depends on B). But wikipedists community is not pure technical and draws images with unexplained and random meanings of arrows. It looks nice and reasonable to have a full circle of arrows, no?
No. The funniest and most obvious nonsense is View --sees--> User
: what does it even mean? Big brother carefully stalking the user with webcamera? The meaning suggests that the arrow direction is reversed, but then we would not have that nice circle of life...
But seriously: the most shocking design flaw of the image is the Model --updates--> View
relation. Technically it allways needs to be View --reads--> Model
. If the Model were active, it would mean that the data objects and actions are dependent on other parts of the system, so it would not be reusable.
The other nonsense is the User --uses--> Controller
. Controller is invisible, users use only View, other parts are blackbox to them. The Controller is basically system of events implementations. The source of the events can be User's input or Model's data change, but they use interfaces and it is the Controller which implements them. (It is called Inversion of Control and because of it some people confusingly draws the arrows in opposite direction.) These actions command Model and View to update, therefore the arrows point from the Controller. Nothing controls Controller. That's why it is called Controller: all control is aggregated into it. Active View is an exception: it can read Model without Controller's blessing if it needs to fill its selectbox for instance. But sometimes View's dependence on Model's interface is undesirable, so not all Views are designed active.
So the correct image is
--- Controller ----
| | !!! arrows mean dependency, not data flow !!!
V V
View ------------> Model
(if active)
The Event Dispatcher
This is the root of confusion that Wikipedia creates: The MVC architecture can't run standalone, it needs Event Dispatcher that handles the events and calls the controller:
- in web applications, it is the HTTP server
- in managed applications, it is auto generated code by IDE (usually hidden from the coder)
- in native applications, it is in the main loop
- in lower level applications, it is provided by system environment
User <--> View --> Event Dispatcher
∧ |
| | !!! arrows mean data flow, not dependency !!!
Model <--> Controller <-----
Now we have the interaction cycle. Note the arrow meaning: from the dependency perspective, Event Dispatcher is of course independent to the Controller, the Controller needs some Event Dispatcher.
To implement the MVC, we need to understand the Dependency Injection technique described on active model scenario below.
Active Model scenario
Sometimes the Model can be also the source of events, i.e. if some account credit drops below some level, it could signal the View to show warning. But the Model should be independent to other part of the system, so it can't call View. The Observer design pattern is the way to implement it, see the simplified example:
Model
Model uses interface to let the View hook to its event of "account too low" or "account too high"
interface AccountObserver {
// in dummy examples, these methods are often vaguely named update()
public void accountLow(int value);
public void accountHigh(int value);
}
class Model {
// protected, not private, to make the Model extensible
protected int account;
protected AccountObserver observer;
// more observers should be allowed, we should have array of observers
// and name the method "register..." instead of "set..."
public void setAccountObserver(AccountObserver o) {
observer = o;
}
public void updateAccount(int change) {
account+= change;
// calculate values ...
if(account<minValue) observer.accountLow(account);
if(account>maxValue) observer.accountHigh(account);
}
...
}
View
Some people would recommend to aggregate Observer rather than implement it. The inheritance is simpler and if the model defines all the observers in a way that their methods have unique names, we can inherit.
class View : AccountObserver {
public void accountLow(int value) {
warning("Account too low! It has only "+value+" credits!");
}
public void accountHigh(int value) {
warning("Account too high! It has above "+value+" credits!");
}
...
}
Controller
In the Controller part of the architecture we put together the user interface (View) and other event sources with Model (which may consist of more than one data sources). In our simplest case:
class Controller {
protected Model model;
protected View view;
public Controller(Model model, View view) { // Constructor
this.model = model; this.view = view;
model.setAccountObserver(view);
}
// called by Event Dispatcher
void onUpdateAccount(int requestedValue) {
if(requestedValue<0) ... // the business logic can be here or in the Model
model.updateAccount(requestedValue); // this updates the View
}
}
Note the model.setAccountObserver(view)
- the model and view objects (as properties of the Controller) are coupled, but the Model and View classes are independent. This Dependency Injection pattern is the key to understand the Model - View relation.
Now to your questions
- Which relationships are correct? All and none. All, because the differences come from different meaning of the arrows. None, because the meaning of their arrows are not explicitly described (or wrong like Wikipedia's image, see Olexander Papchenko's comment).
- Business Logic should be handled in Controller or Model? Both. Pure data operations definitely belongs to the Model, but Model can't decide everything, i.e. when and how the user should log in. This belongs to the Controller and is shown in the code below.
- In case the Controller pass an object to the View, is this object belonged to Model? Yes, see the code below.
- How does the view retrieve data directly from model? Does it have the reference directly to model or it interact with the model coming from Controller? I believe both scenarios are possible: if the View needs to display some static data like Countries list, I see nothing wrong if it has an instance to the Model (maybe via some interface) and call its getter method directly (if the View needs to change data, it creates an event and lets the Controller handle it). This is the arrow
View --> Model
in the image above. If the data is dynamic like getContacts(int userId)
, it needs the Controller to validate the request:
class Controller {
protected Model model;
protected View view;
protected User user;
public Controller(Model model, View view) { // Constructor
this.model = model; this.view = view;
model.setAccountObserver(view);
initBusinessLogic();
}
protected function initBusinessLogic() {
user = view.loginModalDialog(); // active View (needs to get userId from Model)
// passive View alternative
// [login, password] = view.loginModalDialog();
// user = model.authenticateUser(login, password);
// Controller pass object from the Model to the View
if(user.isLoggedIn()) view.setContactList(model.getContacts(user.id));
// if(user.isLoggedIn()) view.setContactList(userId); // less universal
// view.doYourStuff(userId); // wrong, View should not have business logic
}
}
Note Models and Views are usually implemented as multiple classes with separate responsibility (Views for dialogues, main page etc., Models for user manipulation, orders etc.) The Controller is only one per application; if we have specialized controller for each View, it is called Presenter and the architecture is MVP.