ModelViewController is a design pattern (or, some would claim, multiple design patterns) that lets the designer separate data (the Model) from the presentation of that data to the user (the View) from the code that changes the data (the Controller).
Thus, you might have a program that displayed colours as received by different sensors. The Model would have the raw data updated by the sensors. The View might be a colour spectrum on screen with an arrow pointing to the current colour, it might be a box drawn in the colour, it might be the text name of the colour if being sent to a printer, and it might be a sound file if sent to the speaker. The Model has no idea what the View is going to do with its data. When the data changes, the View is alerted to that fact and gets the data from the Model once again.
The Controller is the code that alters the data in the Model. Perhaps there is a calibration required for each sensor, and we have to provide a toolbar button on screen, a menu item, and a keyboard shortcut, all of which allow the calibration to happen. By separating the code which does the calibration out into a Controller object, each of these separate input events can run the same code without duplicating it.
So far, so good. But there are a number of issues that are not reflected by this pattern. By fleshing out the pattern a little, I think it can be more useful. I'm sure other people have done this, but I thought I'd take my own stab at it.
My changes come from watching the development of the
JavaSwing classes. There are a number of design issues that arose there that I think bear examining in light of the
ModelViewController pattern.
For example, there is the whole issue of where sorts and filters should be implemented. Say you need to display the data from the Model in a particular sorted order. If you implement the sort on the Model, you are left with only one order that a View can display. This is a problem if you have several views all requiring different orders.
On the other hand, putting the sort into the View can be incredibly inefficient, especially if, as is often the case, the Model lives on a different machine than the View.
The solution arrived at in
JavaSwing is to borrow from operating system ideas and allow insertion of a Pipe between the Model and View. The Pipe can live on the same machine as the Model, and many Views can share a Pipe or create their own. This solves both problems, and provides a flexible framework for adding all kinds of behaviours that float somewhere between Model and View. You can have a Pipe to sort on a particular key, a Pipe to filter based on some condition, and so on. You could even hook up multiple pipes to create aggregate behaviour such as sorting AND filtering.
If anyone is interested, I can go into more detail about how Pipes are implemented in
JavaSwing.
Another issue that arose in
JavaSwing is the need for a second Model somewhat different from the standard one, one which reflects the state of the View itself. This they call the
GuiModel.
When a scrollbar changes its position an underlying Model changes, but not your application Model. When components are enabled and disabled, those states are stored somewhere, as are the rules for when the states change. Although no
GuiController is mentioned in
JavaSwing, perhaps the rules for state changes should be put in there.
A final issue has to do with how changes to a model are allowed. This is not, strictly speaking, part of
JavaSwing but rather
JavaBeans, which define different kinds of properties for a bean. These properties can be simple, indexed, bound, or constrained. Constrained properties are ones which allow listeners to Veto a change. This makes for a good way to implement Business Rules.
Note that Vetoers could be considered part of the Controller, but I think there are benefits when they are considered separately. A Controller actually changes the Model. A Vetoer just monitors attempts to change the Model and optionally vetos the attempt.
So now we have a more complicated, but I think more useful, pattern which contains
ModelViewController at its heart.
The original
ModelViewController looks something like this (forgive the column of periods):
--> Model --\ .
/ \ .
/ \ .
Controller <----- View .
and
ModelPipeViewController looks more like this:
Vetoer
|
v
--> Model --\ .
/ \ .
/ Pipe .
/ \ .
/ \ .
Controller <------- View .
/ \ .
/ \ .
/ \ .
GuiModel <--- GuiController .
--
BruceAtherton
The pipe stuff reminds me of the
FacadePattern that says to create a wrapper class (the "facade") around a group of classes to simplify their interface. The difference here is in the meaning of "simplification" - instead of simplifying the programming interface, the
ModelPipeViewController is in some sense "simplifying" the model itself. The is easy to see in the case where the pipe strips out some of the detail in the model, but also makes sense in other contexts (a sort pipe decreases the entropy, which is an abstract way to define simplicity). --
BillTrost
I have been thinking about ModelViewController recently, but I have been focusing on how to represent transient cues like rubber bands for drag operations. As far as I can tell, rubber bands are representations of the state of the controller, not of the model.
I am now convinced that the controller should be represented in the view as well as the model. I have just implemented rubber-banding and other visual cues in my applet by linking the controller to the view using the Observer pattern. The controller itself uses the State pattern, and each state object now has the ability to "represent itself" if necessary. For example, the select state draws a gray rubber-band if the user is currently dragging the mouse.
Previously I would have put this functionality somewhere between the model and the view, and I would normally have to peek at the event queue as well (which should be somewhere between the view and the controller).
--
DavidMcNicol
I share the observation given at the beginning of this page that
ModelViewController is just not enough - at least not in most of the software which I have designed.
PacAgent is definitely something to think about when running into problems with MVC, as well as I will consider
ModelPipeViewController in the future. In the past I have, however, found it useful to apply MVC - as I call it - recursively:
RecursiveModelViewController. --
ThomasWeidenfeller
I'm afraid most of you are criticizing your idea of
ModelViewController, not the real thing. The real thing does NOT use controllers to change the data; it uses them to handle user input. This is a big difference. I think you are using Jacobsen's definition of a controller. His ideas are important, too, but it is too bad he used the same name because they are different from
ModelViewController. His controllers are mediators, while those in
ModelViewController are strategies.
VisualWorks has evolved to having two levels of models, an
ApplicationModel and a
DomainModel. Actually, there are three levels if you count
ValueModels. A
ValueModel acts somewhat like your pipes. They provide a very simple interface that implements the ability to get and set a value (i.e. they are a property) and the Subject role of the Observer pattern. A View is a composite, and the component views usually observe
ValueModels. An
ApplicationModel is the model of the entire window, and its variables usually contain
ValueModels. Because
ValueModels are so simple, it is easy to put adapters (or decorators, depending on your point of view) on them. (A
PluggableAdapter can be thought of as a
ValueModel, because it just implements #value and #value: like a
ValueModel, but it changes the return type of #value and the argument type of #value:, so I think of it as an Adapter. Plus, the name!)
I have never used PAC, so I am not an authority on it. However, when I read the book, I decided it was quite a bit different from
ModelViewController, and not really a competitor. It is more for designing GUIs in the large, while
ModelViewController is for designing them in the small.
--
RalphJohnson
I'm not sure I understand why you make a distinction between changing the data and handling user input. The reason I added a second
ModelViewController loop to the first (and perhaps Thomas's recursive pattern is a better solution) is because I see there basically being two types of "handling" that occur with user input. In one case, the model changes. In the other, the state of the GUI changes in some way. I am just explicitly separating the two types of handling. I suppose you could add one more for the starting and stopping of processes. But are there other types to consider?
In any case, it seems clear that at least PART of the Controller's job is to directly or indirectly change the model. Given that, I don't understand how the comments are invalidated, though perhaps you could enlighten me. Go easy on me, though, I am Smalltalk-challenged.
--
BruceAtherton
I learned
ModelViewController by spending a year or so trying to use it. It doesn't take a year to learn
ModelViewController any more, but I think that the only real way to learn it is to play with a real implementation. Except for the one in
SmalltalkLanguage, the only real implementation that I've heard of was one in
ObjectiveCee that you probably can't find any more. If anybody knows of another real implementation of
ModelViewController, please let me know. Note that saying that something is a real implementation implies that you know Smalltalk so you can be sure that you know what the real one is.
More or less by definition,
ModelViewController is the user interface framework in Smalltalk-80. It has changed over the years, so that what I first used in 1985 is different from what is in
VisualWorks 3.0, though you can find something fairly similar to the original right now (November 1998) in
SqueakSmalltalk.
A controller converts user events like key presses and mouse movements into messages that are sent to the model and the view. I think of it as a strategy for handling user input.
A controller sends messages to the model, and most of those messages result in the model changing its state. However, they tend to be at a pretty high level; the model is responsible for changing its own state.
--
RalphJohnson
I agree that having a GUI only controller makes sense. Some real tasks for the Controller could be to coordinate changes of views without to interact with model. It's typically to coordinate two views changes. I also agree that it's better to also have a "GUI Model" in order to abstract the state of the view instead to use direct views states.
But when you can, it will be better to design a composite view with its internal GUI model and controller and use the resulting view in a MVC pattern or something else.
The problem of the MVC pattern is that in practice the Controller has too many responsibilities. Its strength is that for high-level design it is perfect and so simple that it's tempting to adopt it. MPVC, by having 4 items instead of 3, is already too complex to struggle against a 3 items MVC. So the Pattern VeMCPViGmGc has no chance to be popular!
--
BernardDevaux
TheoVerelst little example
http://mini.net/tcl/a%20little%20multiplication%20toy
idea along mvc lines:
[
http://wiki.tcl.tk/automatically generating socket based Tcl / C connection code, 1]
= [
http://mini.net/tcl/11064]
See also:
ModelModelViewController,
ModelViewControllerHistory,
StarTrekMonopoly
CategoryPattern