(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
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
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:
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.
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
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.)
- Let the
Viewdirectly subscribe to the
ObjectAEventevent. 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.