The preceding sections have explained the concepts behind MVC and described how models, views and controllers are connected together. This section completes the picture by showing how MVC works at run- time. We'll use a very simple example—a checkbox which can be either 'on' or 'off. The classes and methods are fictional to make them very simple, but this simple example illustrates the concepts which more complex models, views and controllers build upon.
The diagram above shows the three MVC objects. There is a model (ButtonModel) which has a single boolean variable—one that can take one of only two values, true or false. This variable is called value. There is a view (ButtonView) which is responsible for producing a graphical representation of the state of the value variable in ButtonModel, in the form of a three-dimensional widget on the screen. Finally, there is a controller object (ButtonController) which is responsible for changing the state of the value variable in ButtonModel whenever the view's button widget is clicked on by the user. The following might be a typical sequence of events in the life of these objects:
1. The window in which Butfconview is sitting is opened and so ButtonView has to draw the widget for the first time. To determine the correct look (pressed in or popped out), the view sends the model the message value. The return value from this message will be either true or false, and the view uses this information to decide how to draw the widget.
The MVC Architecture 2. The user comes along and clicks the mouse on the area of the
screen managed by ButtonView. The ButtonController sees this, and enters into a dialogue with ButtonView to determine if the click was actually within the checkbox widget. If it was, the controller must send a message to the model to tell it to invert its state (become true if it was false, and vice versa). Now, the controller doesn't know the current state of the model so it evaluates something like: model value : model value not. If you think very carefully about this expression, and remember the rules of precedence, you'll see that the controller is asking the model for its value (using model value), inverting it (not), and sending the result back to the model (value :).
3. The model has now been changed, and as part of its value: method it sends itself the message changed: #value. This causes an 'update' to go out to all the model's dependents informing them that an object upon which they are dependent has changed.
4. The BufctonView, being one of the model's dependents, receives the update in the form of the update: ttvalue message. Its implementation of update: simply re-executes the code that it used to draw the widget in the first place. This sends the message value to the model to find out the new value, and then draws the widget appropriately.
You should try to remember a number of important points from this example. First, neither the view nor the controller hold onto the model's state (true or false). Every time they need it, they ask for it. Second, the controller doesn't know anything about the visual layout of the widget. When it needs that information, it asks the view. Third, when the controller changes the state of the model, it doesn't directly tell the view. Fourth, the model doesn't know about the view. When its state is changed by the controller, it's only because of the dependency mechanism that the view gets to know about the change. Finally, when the model tells the view that it's changed (using dependency), it doesn't tell the view the new state—it only tells it what aspect has changed (ftvalue, meaning that the instance variable called value has changed). The view has to ask the model for the new state of that variable.
We can now imagine that this example could be extended in a number of different ways. ButfconModel could start holding more information than just a boolean variable. For example, it could hold the
Chapter 9
string which would be used by the view to label the checkbox. Bufctonview would then have to send an additional message to retrieve the label from the model before displaying it. Also, instead of
executing self changed: frvalue to let its dependents know it has changed, ButtonModel could be more helpful by executing self
changed: ftvalue with: self value. This would pass the new
value of the value variable directly on to the dependents, thus avoiding the need for them having to ask for it.
Finally, notice how the diagram shows that an unknown 'third party' (not ButfconController) could also change the state of BufctonModel by sending it a value: message. To the model, this is indistinguishable from the controller doing it, and so the dependency mechanism still kicks in, allowing the view to reflect the new state of the model correctly.