MVC Design Patterns – Who Handles Observers?

design-patternsmvcobserver-pattern

(I'm writing a large MATLAB GUI that makes significant use of MVC, so my example is written in MATLAB. However, I believe this question is language-agnostic. Please correct me if I'm wrong.)

I have a class Model which is obviously the model for my MVC application. Suppose I have the following:

classdef Model < handle
    properties
        objectA
        objectB
        objectC
    end
end

objectA, objectB, and objectC are all objects that can be observed:

classdef objectA < handle
    events
        ObjectAEvent
    end
    methods
        function raise(this)
            this.notify('ObjectAEvent', someEventData);
        end
     end
end

etc.

Now say I want my View to respond to changes to my Model. In particular I want the View to respond to the ObjectAEvent event. There are two ways to do this:

  1. Let the View directly subscribe to the ObjectAEvent event. We've now coupled the View into the internals of the Model, which I believe violates the Law of Demeter. I'm pretty sure this also violates the concept of MVC by definition.

  2. Let the Model "forward" the event to the View, as follows.

    classdef Model < handle
        properties
            objectA
            objectB
            objectC
    
            listeners
        end
        events
            eventFromObjectA
            ...
        end
        methods
            function this = Model
                this.listeners(1) = addlistener(this.objectA, 'ObjectAEvent', @(src, eventdata) this.notify('eventFromObjectA', eventdata);
                ...
            end
        end
    end
    

    Now the View directly observes the Model, but the Model has to pass the events and associated data to the View. I suppose this is kind of the point of MVC, but now there's a coupling between each object_ and the Model directly. I suppose the Model ought to know about his object_s, but this still feels… clunky.

Which approach is more correct? Are there other alternatives which are cleaner than either of these?

(Answers may have examples in any OOP language; I'm just most familiar with MATLAB.)

Best Answer

  1. Let the View directly subscribe to the ObjectAEvent event. We've now coupled the View into the internals of the Model, which I believe violates the Law of Demeter. I'm pretty sure this also violates the concept of MVC by definition.

MVC isn't about total decoupling. It's about avoiding coupling to elements that are unstable. As for Law of Demeter, you'd have to show why you think it violates it. It's not a hard and fast principle, either, despite its name having the word "Law" in it. It's nearly impossible not to violate it at some point.

View classes tend to be less stable than the model classes, because views are part of the user interface. Users tend to want new ways to view information (it's hard to get the views right the first time), etc. E.g. how many times has the GUI for Microsoft Word changed, yet the model of a document (think of paragraphs, words, characters, fonts, styles, etc.) has not changed much?

In MVC, views can be directly coupled to the model classes, because model classes tend to be more stable. MVC makes this assumption as a design choice. If model classes change (it can happen), then all bets are off for those changes being isolated to the model. You'll probably have to change the views, too.

Model classes have to communicate with the Views, but MVC wants to avoid direct coupling. We get around this problem by disguising Views as "Observers." The Observer API is very stable, even if the views that implement it are not. So as far as I understand MVC, it's OK to have coupling the way you have described it in point #1.

Let's use a real object rather than ObjectA, say engineTemperature. The view that displays the temperature would surely know what it's displaying. It might add the units "degrees C" since the view knows the value is a temperature. It might use the color red if the temperature exceeds some upper value. It's normal for views to be directly coupled to the model elements they display.

The other way around, however, is different. engineTemperature should not know how it's being displayed, what colors are being used, who's displaying it, etc., since that knowledge would make it tightly coupled to the views, and it would lose its stability. Any change in the view might "break" the temperature object. So, with MVC and Observer, engineTemperature (as a Subject in the Observer pattern) only knows it has Observers, which all support the Observer API.

Have a look at http://martinfowler.com/eaaDev/uiArchs.html#ModelViewController for more info on MVC and other UI designs.

Related Topic