Joseph Bergin, 1996-1999
A user-centered (event driven) application can be divided into three kinds of classes- a model, implementing basic functionality, one or more views, implementing the "look and feel" of the application, and for each view, a controller to give the human user control over the application. The view incorporates both visual elements of the user interface and the controller represents control mechanisms for the application. (MVC was originally a basic design paradigm in Smalltalk. It is discussed extensively in the Smalltalk literature. )
As an example, in a spreadsheet program built with the model-view-controller methodology, the model would be a set of basic equations defining the relationships between cells in the spreadsheet. There is no visual or control mechanism. However, the class implementing the model provides getter and setter methods for all important model parameters (variables). Getter methods get information from an object--usually just the values of instance variables, but more generally, any pertinent information. Setter methods give information to the object--often just new values for instance variables. The "interface" of the model is just a set of function interfaces.
In Java, a model (or part of a model) is a class that extends the Observable class. A number of the methods will be discussed below.
To continue the example, a view in the spreadsheet program might be the normal rows and columns view that we normally associate with a spreadsheetAnother view might be a graphical view of part or all of the spreadsheet, such as a bar-chart or pie-chart. The different views might be visible simultaneously in different frames, or alternately visible as appropriate to the application. The views can run in separate threads if needed.
In Java, a view is a class that implements the Observer interface. As such it must implement the update method:
public void update(Observable 0, Object arg);
This method will be called by a model object whenever the model changes as discussed below.
For each view in the application there are a number of buttons and text entry fields for giving commands to the model. These represent the controllers, though to the user they appear to be part of the views.
The controllers in java are event listeners such as ActionListener and MouseListener.
The way that this system works is as follows. The programmer creates a model and at least one view. The model object is constructed first and then the views. Each view is given a set of controls and each control is given one or more event liseners. Each view "registers" with the model by sending it the addObserver message. The model keeps a list of all registered views. A view can also de-register if appropriate. Likewise, each listener registers with the Java component that it will handle events for. This is done with methods such as addActionListener.
When a model changes, either because of internal computations, or because an external agent (a controller) has called one of its setter methods, it sets its own member variable "changed" to true and executes its method notifyObservers. This latter function sends the update message to all registered views with a reference to the changed model, and an additional reference parameter that can be an object of any type.
When a view gets the update message, it can use the passed object to decide what to do. It usually polls the model (calls getter methods of the model), to determine if information important to the view has changed. If so, it updates the display as appropriate. A view can also query the model as to whether it has changed by sending it the hasChanged message. If true is returned, the view can query for values and update itself as needed.
The user than "looks at" the view and manipulates the controller to update the model. User control is achieved when the user manipulates one of the control components. This component sends messages to the model (setter methods), that cause the model to update and start the notify process in motion. This causes ALL views to be updated, not just the one the user manipulates.
Notice that several views can be kept synchronized with this mechanism. It is also relatively easy to add new views to an application, since the underlying model generally doesn't need to be modified to do so. It is also somewhat easier to update the model for new functionality, since the interface and the functionality are kept separate.
Also note that the view and its controllers can be fairly tightly coupled. The usual mechanism is to make the controller (listener) classes inner classes to the view elements that they correspond to.
More than anything, however, the model-view paradigm is just a way of thinking about user-centered software that gets us to clearly separate interface elements from functionality elements. It doesn't depend on a framework, for the necessary elements can be quite easily built in C or other languages. It leads to enhanced portability (of the model part at least) because system specific user-interface elements are not mingled with the basic functionality. The spreadsheet applet on my Java page (Start at my home page http://csis.pace.edu/~bergin/ and follow the Java links.) was organized using model-view-controller ideas, but without using the Observer-Observable framework of the Java libraries. The source code is available for reading from the Applet page.
In Java you can actually think of a Model as a collection of observables rather than a single one. This can give you finer grained control over your application. Each observable in a model can then have its own observers. Each cell in a spreadsheet could be an observable with its own views. Since Java is a single inheritance language (of classes, anyway), it is a bit of a restriction that models must inherit from the Observable class. The tradeoff, however, is that all of the scaffolding of registering observers and notifying them is handled by the Obserable superclass and doesn't need to be implemented for each model. Note, however, that when it is impossible to inherit from Obsrveable, the "model" can always delegate the function to an artifically constructed Observable member that it uses for the purpose.
Here is a sample application that uses these ideas. There is a model class (TemperatureModel.java) that maintains a temperature and knows how to return it in either degrees Farenheit or degrees Celsius. The Gui classes (in MVCTempConvert.java) define the graphic user interfaces (Views). Each of these has a controller consisting of three action listeners. Notice that the model knows nothing about its views, other than that they are registered Observers. The two views know nothing about each other, and yet they are simultaneously updated.
The above is discussed briefly in Java in a Nutshell (David Flanagan, O'Reilly & Associates, 1996, pg. 343-4) and more extensively in On to Java (Winston & Narasimhan, Addison-Wesley, 1996, pg. 239ff).