Tutorial
Menus

MVC Pattern - MVC Design Patterns

MVC - model-view-controller

Rating: 4.4/5 (5 votes cast)

Level   : Advanced
Author : Arunkumar S
Download Source : HeartBeat.java
Download Source : HeartView.java
Download Source : HeartController.java
Download Source : HeartBeatMain.java

the model-view-controller (MVC) design pattern

the heartbeat model

Our model of the heart (source) will be a pretty simple loop :

public void run() {
while (running) {
numberOfBeats++;
updateObservers();
try {
Thread.sleep(SLEEP_DURATION * excitementLevel);
} catch (InterruptedException e) {
// do nothing if interrupted
}
}
}

Each time through the loop, we increment the number of beats, and continue to loop until running is false. running is a boolean flag to represent the state of the model. The method stopHeart that is used to set running to false. Unfortunately, the heart cannot be restarted.

public void stopHeart() {
running = false;
}

Likewise, the model provides a method for adjusting the excitementLevel - adjustExcitementLevel which adds the amount passed in to it to the current excitementLevel.

public void adjustExcitementLevel(long delta) {
excitementLevel += delta;
if (excitementLevel < 1) {
excitementLevel = 1;
}
}

These are the only methods available to the controller objects. These methods define the model's API and there are no other ways of altering the model's state.

The views are updated via the updateObservers method. It calls the setChanged method within the Observable class, then uses the Observable class's notifyObservers method passing an Integer object containing the value of the current heart beat. The notifyObservers will call the update method in each of the registered Observer objects.

Let's look closely at the controller object now.


the heartbeat controller

This controller (source - most of the code was generated by Symantec's Visual Cafe...the code I added is at the bottom of the file.) has its own frame where it presents the user with three options: bore, excite, and stop. The "stop" button will call the stopHeart method in the model. The "bore" and "excite" buttons both call the adjustExcitementLevel in the model. The difference is that "bore" will trigger a call with a positive amount (to increase the delay) and "excite" will trigger a call with a negative amount (to decrease the delay).

I haven't mentioned one more controller that this application has. It is a special controller that needed to be added when the application was put into an applet (source). That is, we want the model to stop when we leave the page. If it didn't, there would be a continuous heartbeat sound made as long as the user's browser was running. This is due to the model having its own thread (created by the HeartBeat class), which calls the update method within the applet. The applet's thread ends when the user leaves the page, but the HeartBeat isn't stopped. So, this applet's stop method (which is invoked when the user leaves the page the applet is on) acts as a very simple controller, calling the model's stopHeart method to stop the HeartBeat. Notice how we've been able to adapt the various model methods in order to create a more friendly user interface.

Implementation note

Some MVC descriptions will suggest linking the view to the controller, but that just adds another level of coupling that hasn't seemed necessary to me (yet?). They suggest that the controller might need to control parts of the view - which I think should just be part of the view. Likewise, if the controller's display relies on the state of the model (in order to display the appropriate buttons or messages), it should be a view in its own right. Sure, the effect can be faked, with the controller maintaining its own variables for the model's supposed state - but this gets messy (bug prone) quickly . Imagine situations where there is more than 1 controller (multi-user, or just multiple ways of affecting the model). Maybe it is because I'm still getting a feel for the MVC pattern, but I prefer keeping the elements pure, where they know as little about each other as possible.

Another trap one might fall into is confusing view controls with model controls. 

A view might be a graph, and the user might want to control how the graph displays a few things (x and y ranges and perhaps scatter plot versus line graph vs bar). Those could be controllers on the view, but I wouldn't put them with any controller of the model. The view params in this case are totally independent of the model, so the controls are safely separated from the model and other controllers and other views.

Now, with that out of the way, we can take a look at how the views work...


the heartbeat view

The views in this app are very simple. The basic view (source - again, most of the AWT related code was created with Visual Cafe) has a constructor that takes a model and registers for updates from it. The update method uses the current heart beat count (in the data object passed to the update method) as the new value for the display label. For this application, I decided that the view needs to know the heart beat count from the model in case it joins the application late. When a view is created, the heart could have been beating for a while already. In more substantial applications, this information might be essential, even though it isn't in this application. Just to illustrate potential problem, I made it an issue in this toy application. Similarly, the number of heartbeats that the view has received can be kept locally (by the view), in cases where that information is important.

The applet (source) is a view as well. Its update method doesn't rely on the heart beat count, because it just plays a sound for each heart beat. It is pretty straightforward.

Implementation Note

In the applet case, there was some data sent that wasn't used (the heartbeat number was ignored), which some could consider wasteful. In fact, if the model provided an accessor method for the view to use for obtaining the current heart beat, then there would be no need for the current heart beat to be sent as data in the model's notifyObservers method. Instead, a null value could be sent during the update. Then, if a view needed the current heart beat, it could access it directly from the model, which is always passed to the updatemethod.

But this model doesn't have any accessors like that. It could - and it's easy to argue that having views get their data directly from the model is a better design:

  • it allows views to obtain from the model specific information for that particular view. Only the necessary information is transferred.
  • no data bundling/carrying objects need to be created. Eliminating a middle-man between models and views
  • no extra overhead of object creation during observer updates.
  • as the model grows, views are all that need to be updated - again, no middle-man classes need to be maintained as well.
But passing data update objects has advantages too:
  • no concurrency problems - if the model runs in a higher priority thread, the view might miss some data points if it has to access the model directly for its data. This can be a serious problem.
  • data abstraction - I use the same text based view with all of my applications...the text based view doesn't need to know what data is important to a particular model, as the update data object defines that (and how to print it...).
  • easier to distribute the model and view on different machines if they pass messages/data objects to each other, instead of making application specific calls upon each other. With message passing, all the models and views will have a common interface (allowing the same proxies to be re-used). in distributed applications, getting each data point (concurrency problem) becomes more complicated, as one has to deal with a variety of network conditions.

It really depends on how complicated your application is going to be and whether or not you want to distribute it. Personally, I prefer the data update object approach. I'm not too concerned with efficiency right now - machines and JVM implementations will get faster and I'm satisfied with letting those engineers/developers concentrate on improving my run-time performance. Distributing my applications also helps trim my run-times as well and the data update object approach lends itself nicely to being distributed. But I tend to use the data update object method mainly because it helps me focus on what information about the model is important. I'm forced to do that when designing the data update objects.

Again, it's the design process that MVC has helped tune for me. I'm asking better questions about the objects in my application, their functions, and what information they should have access to and provide. Since I find it is still an evolving process in my own head, it is probably something you probably should play around with too, in order to find out what you like and don't like.





< Previous 1 | 2 | 3 | 

Discussion about this tutorial

  Start a new Discussion | Read All Discussion
Subject RepliesLast Post
Javaorigin.com contact@javaorigin.com