MVC pattern. The relationship between Model, View and Controller
Asked Answered
L

2

9

The relationship between Model, View and Controller make me confused.

This topic shows an arrow form View to Controller, an arrow from Controller to Model and an arrow from Model to View: http://www.codeproject.com/Tips/31292/MVC-v-s-MVP-How-Common-and-How-Different

However, this topic shows a dual-arrow between Model and View; a dual-arrow between View and Controller ; and an arrow from Controller to Model: http://www.codeproject.com/Articles/288928/Differences-between-MVC-and-MVP-for-Beginners

Finally, this topic shows an arrow from View to Model, an arrow from Controller to Model and an arrow from Controller to View: http://www.w3schools.com/aspnet/mvc_intro.asp

I have some questions:

  1. Which relationships are correct?
  2. Business Logic should be handled in Controller or Model? I've read somewhere that the business logic shouldn't be placed in Controller (ASP.Net MVC)
  3. In case the controller pass an object to a view, is this object belonged to Model?
  4. 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?
Lavinalavine answered 12/3, 2015 at 8:47 Comment(0)
R
9

I find all of the images you're linking to confusing. This image (taken from Wikipedia) explaines it best.

MVC diagram

How It Works

MVC considers three roles. The model is an object that represents some information about the domain. It's a nonvisual object containing all the data and behavior other than used for the UI.

The view respresents the display of the model in the UI. Thus, if our model is a customer object our view might be a frame full of UI widget or an HTML page rendered with information from the model. The view is only about display of information; any changes to the information are handled by the third member of the MVC trinity: the controller. The controller takes user input, manipulates the model, and causes the view to update appropriately. In this way UI is a combination of the view and the controller.

-- Quoted from Patterns of Enterprise Application Architecture by Martin Fowler

Your questions

  1. MVC is about separation of concerns, not about relationships.
  2. Business Logic should be in the model. The controller is only for interacting with the user.
  3. Yes (most likely)
  4. Typically the view fetches the necessary information from the model. When using passive views, objects (from the model) are passed from the controller. Important is that the view only reads from the model and never writes/updates it.

    The View observes and responds to changes in model. The model is the Domain Model rather than an individual recordset or entity.

Errata

How MVC is commonly used in the present time differs from the original MVC pattern as it was coined by Martin Fowler. He based this pattern in Smalltalk.

At the heart of MVC, and the idea that was the most influential to later frameworks, is what I call Separated Presentation.

Another part of MVC is how the model, view and controller interact.

In this case all the views and controllers observe the model. When the model changes, the views react.

This is very different from MVC as made popular by Ruby on Rails, where the controller is responsible for preparing and loading the view.

class ArticlesController < ApplicationController
  def create
    @article = Article.new(article_params)

    if @article.save
      redirect_to @article
    else
      render 'new'
    end
  end

Martin Fowler condenses MVC down to this

  • Make a strong separation between presentation (view & controller) and domain (model) - Separated Presentation.
  • Divide GUI widgets into a controller (for reacting to user stimulus) and view (for displaying the state of the model). Controller and view should (mostly) not communicate directly but through the model.
  • Have views (and controllers) observe the model to allow multiple widgets to update without needed to communicate directly - Observer Synchronization.

-- Quoted from GUI Architectures by Martin Fowler

Raine answered 12/3, 2015 at 8:56 Comment(6)
Regarding your point 4: actually, usually (and as your image and quote shows) the controller does not pass objects to the view, but the view fetches the necessary information from the model. This can be caused by an action by the controller, or the view directly listens to the model for changes. Only in the version of "Passive View" does the controller pass the data to the view.Participate
@Participate Thanks, modifiedRaine
read Martin Fowlers article recently about MVC.The thing is that Wikipedia image is wrong. In classical Smalltalk MVC view is observer of model. article martinfowler.com/eaaDev/uiArchs.htmlGullett
May I ask why did you stroke the answer to the question 4?Overblouse
While MVC is often implemented like that, it's not how it's originally described by Fowler.Raine
@OleksandrPapchenko: However, could not the "updates" arrow be understood as an observer relationship? After all, an observable "updates" its observers, so the model does, indeed, "update" attached views - it just doesn't know they are views, only event receivers.Lejeune
C
8

Wikipedia is not a technical manual

enter image description here

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

  1. 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).
  2. 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.
  3. In case the Controller pass an object to the View, is this object belonged to Model? Yes, see the code below.
  4. 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.

Coup answered 18/4, 2018 at 18:51 Comment(3)
"the View can also register its Model(s) (outside of the Controller) ---> and call the Model's methods directly <---" hope you are refering on getters, because if not... I am so in dark after a spot of light...Bumf
@BoteaFlorin you are right, very good point. In good separation of code the View may call only getters to set its controls (like fill selectbox with data), anything else is not its concern. If the View wants to call some of the Model's setters (like clicking the submit button) it just creates an event and the Controller decides what to do (i.e. the Controller checks if the event is valid in current state). In the web application, the controller handles all HTTP requests, the View creates them (the requests can also come from other endpoints) and the HTTP server acts like event dispatcher.Overblouse
@BoteaFlorin The event dispatcher is not part of the Controller BTW. If your application is not managed by HTTP server, the event dispatcher is usually in the main loop. If you use visual programming in some IDE like MSVC, the dispatcher and the main loop is auto generated i.e. by calling something like Application.Start(new Form1()) which calls event handlers in Form1 instance.Overblouse

© 2022 - 2024 — McMap. All rights reserved.