Model View Controller paradigm

Hello -- I'm trying to get some practice with the model-view-controller design pattern for programming, and I want to make sure that I understand it correctly. The whole point of MVC is that each aspect of the program (model, view, controller) is seperated completely and cleanly from the other aspects so that one can be changed easily without affecting the other two. What I'm unsure of with this, though, is how the three pieces interact and communicate with each other when you do. The only solution to this question that I have figured out is to pass each object to the other two and have them store the reference as part of the class.

class model

{

controller l;

}

class view

{

controller l;

}

class controller

{

model m;

view v;

}

Is this the "correct" way to accomplish this? Or is there an easier/better way?

Ihave coded up a mine sweeper-ish type program using MVC with the style example above and it *works*, but that doesn't mean that it's what's actually used in the industry. Please let me know if that's correct or if it's done differently.

[1414 byte] By [JJCoolBa] at [2007-11-27 2:10:31]
# 1
Check out this recent thread for a discussion of this: http://forum.java.sun.com/thread.jspa?threadID=5164529
hunter9000a at 2007-7-12 2:02:37 > top of Java-index,Java Essentials,New To Java...
# 2

[url #" style="display: block; background-image: url('http://upload.wikimedia.org/wikipedia/commons/thumb/2/2e/ModelViewControllerDiagram.svg/321px-ModelViewControllerDiagram.svg.png'); width:321px; height: 151px] [/url]

Description:

A simple diagram depicting the relationship between the Model, View, and Controller. Note: the solid lines indicate a direct association, and the dashed line indicate an indirect association (e.g., observer pattern).

Often, the model maintains a collection of view objects, not just one.

DrLaszloJamfa at 2007-7-12 2:02:37 > top of Java-index,Java Essentials,New To Java...
# 3
Another diagram:[url #" style="display: block; background-image: url(' http://java.sun.com/developer/technicalArticles/javase/mvc/images/Figure1.gif'); width: 550px; height: 385px] [/url]From this article: http://java.sun.com/developer/technicalArticles/javase/mvc/
DrLaszloJamfa at 2007-7-12 2:02:37 > top of Java-index,Java Essentials,New To Java...
# 4

> Check out this recent thread for a discussion of

> this:

> http://forum.java.sun.com/thread.jspa?threadID=5164529

[quote]Yes. And in fact in the proper MVC model, the controller has references to both view and model, but the view has only reference to the model.[/quote]

That's what I've done above.. Apart from giving the view access to the model. (In my mine sweeper program, the controller variable in my view class was ONLY used to register actionListeners on my components) However, the controller (since it's mine sweeper) is the object that's updating the text on the buttons.. I guess technically that's incorrect. But, at least, I can say that the following is more correct than what I listed first?

class model

{

}

class view

{

model m;

}

class controller

{

model m;

view v;

}

Will the model ever need a reference to the controller? A correctly designed controller should pretty much have only event listeners inside of it, yes? If that's the case, I don't see a situation when the model would ever need to directly call some method of the controller.

JJCoolBa at 2007-7-12 2:02:37 > top of Java-index,Java Essentials,New To Java...
# 5

I think you can segregate MVC layers by introducing three seprate layers:

Model:

Provide some code which access a database and does something with it,push or pull data.

getData(){// data accessing code}

Controller/Business Object:

Provide method(s) which works as a wrapper to access DB(Model) layer

getPurchaseOrderList(){

//access method of Model layer

}

View:

viewPurchaseOrderInDataGrid(){

//access method from Controller layer

}

Here you see, all code units are seperate from each other and can me modified without affecting one another.This is a very simple example to implement a MVC design pattern.I hope it helps.

I hope , you would like to explore for more upcomin things beyond design patterns :

http://planetjavajee.blogspot.com/

Do send in your comments and suggestions..

Happy learning..

pundeera at 2007-7-12 2:02:37 > top of Java-index,Java Essentials,New To Java...
# 6

One more thing: there an obverser pattern relationship between the model and the views, so the model will have a reference to the view, and often a collection.

http://en.wikipedia.org/wiki/Observer_pattern

In fact, many people save MVC isn't really a pattern, but an aggregate, or dog pile, of patterns.

DrLaszloJamfa at 2007-7-12 2:02:37 > top of Java-index,Java Essentials,New To Java...
# 7

> Another diagram:

> From this article:

> http://java.sun.com/developer/technicalArticles/javase

> /mvc/

I appreciate the diagrams, Dr, but I've seen them already and, unfortunately, while they describe the associations visually (which is part of my current understanding), they don't quite explain how it actually works out in code. :( Which is why I'm asking about that aspect of it.. But ... the 2nd diagram you have there suggests that the solid arrows mean that the object has to have a direct reference to the place it points to (as in, controller has a model and a view that it knows about, and the view has a model that it knows about).. Which is what I posted just above this.. So that's helpful also. But also in the 2nd diagram, it shows an event arrow going from the model to the view.. That would mean that the view listens to changes in the model .... how would you accomplish this? Would I need to write methods inside my model that created/threw (?) events?

JJCoolBa at 2007-7-12 2:02:38 > top of Java-index,Java Essentials,New To Java...
# 8

I'll post my (granted messy) mine sweeper program so you can point out which parts I probably coded incorrectly. (If you have time/don't mind)

it's 202 lines long..

import java.util.Random;

import java.awt.Dimension;

import java.awt.GridLayout;

import java.awt.Insets;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import javax.swing.JFrame;

import javax.swing.JButton;

import javax.swing.JPanel;

public class minesweep

{

public static void main(String[] args)

{

controller l = new controller();

view app = new view(20,15,l);

model game = new model(20,15,l);

l.setView(app);

l.setModel(game);

app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

app.setVisible(true);

}

}

/**

The model for a minesweeper game

*/

class model

{

boolean[][] grid;

int mines;

ActionListener l;

public model(int w, int h, ActionListener list)

{

l = list;

grid = new boolean[w][h];

mines = w*h/3;

placeMines();

}

/**

A method to place the mines onto the grid.

It is only used by the constructor.

*/

private void placeMines()

{

for (int i = 0; i < grid.length; i++)

for (int j = 0; j < grid[i].length; j++)

grid[i][j] = false;

Random rand = new Random();

int x, y;

boolean flag;

for (int i = 0; i < mines; i++)

{

flag = false;

while (!flag)

{

x = rand.nextInt(grid.length);

y = rand.nextInt(grid[x].length);

if (grid[x][y] == false)

{

grid[x][y] = true;

flag = true;

}

}

}

}

/**

A method to determine if there's a bomb on a square or not.

@param x the x value to check.

@param y the y value to check.

*/

public boolean isBomb(int x, int y)

{

boolean val;

try

{

val = grid[x][y];

}

catch (ArrayIndexOutOfBoundsException e)

{

val = false;

}

return val;

}

/**

A method to report how many bombs are around a square

@param x the x value to check.

@param y the y value to check.

*/

public int reportBomb(int x, int y)

{

int n = 0;

for (int i = -1; i <= 1; i++)

{

for (int j = -1; j <= 1; j++)

{

try

{

if (i == 0 && j == 0) ;

else if (grid[x + i][y + j] == true)

n++;

}

catch (ArrayIndexOutOfBoundsException e)

{

}

}

}

return n;

}

}

/**

The view for a minesweeper game

*/

class view extends JFrame

{

JPanel p;

ActionListener l;

public view(int x, int y, ActionListener list)

{

super();

l = list;

p = new JPanel();

p.setLayout(new GridLayout(y,x));

for (int h = 0; h < y; h++)

{

for (int w = 0; w < x; w++)

{

p.add(new mineButton(w, h, l));

}

}

this.getContentPane().add(p);

pack();

setResizable(false);

}

}

/**

The controller for a minesweeper game

*/

class controller implements ActionListener

{

model data;

view GUI;

public void actionPerformed(ActionEvent e)

{

mineButton src = (mineButton) e.getSource();

if (data.isBomb(src.getX(), src.getY()))

{

}

else

{

src.setText(String.valueOf(data.reportBomb(src.getX(), src.getY())));

}

src.setEnabled(false);

}

public void setModel(model m)

{

data = m;

}

public void setView(view v)

{

GUI = v;

}

}

/**

A button used for the game

*/

class mineButton extends JButton

{

int x;

int y;

public mineButton(int w, int h, ActionListener l)

{

super();

x = w;

y = h;

addActionListener(l);

setPreferredSize(new Dimension(15,15));

setMargin(new Insets(0,0,0,0));

}

public int getX()

{

return x;

}

public int getY()

{

return y;

}

}

JJCoolBa at 2007-7-12 2:02:38 > top of Java-index,Java Essentials,New To Java...
# 9

> That would mean that the view listens to changes in the model ....

> how would you accomplish this? Would I need to write methods inside my

> model that created/threw (?) events?

(The prefered buzzword is raised: the model raises events.)

This model-view relationship is the classic observer pattern I mentioned

a couple posts ago. As an example of coding it, check out the initial discussion

in the class javax.swing.event.EventListenerList:

http://java.sun.com/javase/6/docs/api/javax/swing/event/EventListenerList.html

Also, that other thread is getting into the details of how GUI events get from the view to the controller: http://forum.java.sun.com/thread.jspa?threadID=5164529

DrLaszloJamfa at 2007-7-12 2:02:38 > top of Java-index,Java Essentials,New To Java...
# 10

> (The prefered buzzword is raised: the model

> raises events.)

*blush* hehe

> Also, that other thread is getting into the details

> of how GUI events get from the view to the

> controller:

> http://forum.java.sun.com/thread.jspa?threadID=5164529

That's one issue that I feel comfortable with for the most part. GUI event generating is pretty straight forward to understand.. But a model (where there is only data and methods to access/modify data) causing events with no visual interaction of a component listening to something is less straight forward.. XD Anyway -- which "other thread" are you referring to? The one Hunter posted initially? Or the one you posted initially? (I've already looked at Hunters, but I won't have time to check yours out until after work today)

edit: n/m .. didn't see you added the thread link there.

JJCoolBa at 2007-7-12 2:02:38 > top of Java-index,Java Essentials,New To Java...
# 11
So .... in my mine sweeper program.. If I were to have my "reportMine" method send an event to the view to update the display of the mineButton (as opposed to the controller doing it directly) ... that would be closer to the correct way to code it under MVC?
JJCoolBa at 2007-7-12 2:02:38 > top of Java-index,Java Essentials,New To Java...
# 12

As far as the model raising events: it's a clean way to keep the model loosely coupled to the view.

Don't think of events (event raising and handling) as just a GUI feature.

It's a completely general paradigm, and one that a lot of code would

benefit from, if used more widely (and wisely).

DrLaszloJamfa at 2007-7-12 2:02:38 > top of Java-index,Java Essentials,New To Java...
# 13

> So .... in my mine sweeper program.. If I were to

> have my "reportMine" method send an event to the view

> to update the display of the mineButton (as opposed

> to the controller doing it directly) ... that would

> be closer to the correct way to code it under MVC?

I haven't had a chance to review your code, but that sounds right.

Usually the controller doesn't change the view to reflect state change in

the model. Instead, the model raises events to notify the view. This is because,

sometimes you have multiple views and a controller may not be aware of all of them.

A simple example of multiple views would be if your minesweeper had a split screen

to help display a large board, or you created a ScoreBoard as a simple view

to just display the current score.

DrLaszloJamfa at 2007-7-12 2:02:38 > top of Java-index,Java Essentials,New To Java...
# 14

> As far as the model raising events: it's a clean way

> to keep the model loosely coupled to the view.

> Don't think of events (event raising and handling) as

> just a GUI feature.

> It's a completely general paradigm, and one that a

> lot of code would

> benefit from, if used more widely (and wisely).

*nods* My point was simply that having a GUI in front of you makes event raising more conceptually understandable. ^.^ Could you provide me with a (simple) method that would raise an event that's NOT associated to a component? I understand the concept, just not the implementation.

JJCoolBa at 2007-7-12 2:02:38 > top of Java-index,Java Essentials,New To Java...
# 15

> Could you provide me with a (simple) method that would raise an event

> that's NOT associated to a component? I understand

> the concept, just not the implementation.

Your model could raise a ModelStateChange event when its state is changed.

Your model could have a EventListenerList field and then the code involved

would be a simple copy-paste-edit of what is described in that class.

DrLaszloJamfa at 2007-7-21 20:20:18 > top of Java-index,Java Essentials,New To Java...
# 16

> Your model could raise a ModelStateChange event when its state is changed.

> Your model could have a EventListenerList field and then the code involved

> would be a simple copy-paste-edit of what is described in that class.

Ok .. I think I see what you're referring to in the EventListenerList on the API. Slightly confusing for now, but I'll read it closely and think about it and try a sample program to see if I can get it.. But I *don't* see a "ModelStateChange" event in the API.. I imagine that would be an event object that I coded myself?

class modelStateChangeEvent extends AWTEvent (?)

{

// my event code

}

yes/no?

JJCoolBa at 2007-7-21 20:20:18 > top of Java-index,Java Essentials,New To Java...
# 17
BTW - I'm gonna give you 8 dukes, Dr, and I'll give Hunter 2 for the help on this when I get off work today also.
JJCoolBa at 2007-7-21 20:20:18 > top of Java-index,Java Essentials,New To Java...
# 18
Hang on, I'll whip up a quick example...
DrLaszloJamfa at 2007-7-21 20:20:18 > top of Java-index,Java Essentials,New To Java...
# 19

Here is the example. It mainly shows how to use EventListenerList.

import java.util.*;

import javax.swing.event.*;

interface ModelListener extends EventListener {

public void modelStateChanged(ModelChangedEvent evt);

}

class ModelChangedEvent extends EventObject {

private static final long serialVersionUID = 0;

public ModelChangedEvent(Model source) {

super(source);

}

public Model getModel() {

return (Model) getSource();

}

}

class Model {

private EventListenerList ll = new EventListenerList();

private ModelChangedEvent modelEvent = new ModelChangedEvent(this);

public void addModelListener(ModelListener l) {

ll.add(ModelListener.class, l);

}

public void removeModelListener(ModelListener l) {

ll.remove(ModelListener.class, l);

}

protected void fireModelChangedEvent() {

Object[] listeners = ll.getListenerList();

for (int i = listeners.length-2; i>=0; i-=2) {

if (listeners[i]==ModelListener.class) {

((ModelListener)listeners[i+1]).modelStateChanged(modelEvent);

}

}

}

private int sampleState;

public int getSampleState() {

return sampleState;

}

public void setSampleState(int newState) {

sampleState = newState;

fireModelChangedEvent();

}

}

class SampleModelListener implements ModelListener {

public void modelStateChanged(ModelChangedEvent evt) {

System.out.println("SampleModelListener sees new state of " + evt.getModel().getSampleState());

}

}

public class ModelExample {

public static void main(String[] args) {

ModelListener l = new SampleModelListener();

Model m = new Model();

m.addModelListener(l);

//do some state changes

m.setSampleState(10);

m.setSampleState(9);

m.setSampleState(8);

}

}

DrLaszloJamfa at 2007-7-21 20:20:18 > top of Java-index,Java Essentials,New To Java...
# 20

ok Thanks Dr. I will check it out (yet again) when I'm off work today. I appreciate it greatly. I was also wondering if there might be any way I could get contact info from you? (If you don't mind if I shoot you an email or something from time to time about this stuff) No worries if you aren't comfortable with that.

JJCoolBa at 2007-7-21 20:20:18 > top of Java-index,Java Essentials,New To Java...
# 21
I'm always lurking here. And there's lots of smart people here, so just throw it out into the forum...
DrLaszloJamfa at 2007-7-21 20:20:18 > top of Java-index,Java Essentials,New To Java...
# 22

protected void fireModelChangedEvent() {

Object[] listeners = ll.getListenerList();

for (int i = listeners.length-2; i>=0; i-=2) {

if (listeners[i]==ModelListener.class) {

((ModelListener)listeners[i+1]).modelStateChanged(modelEvent);

}

}

}

I haven't looked at the EventListenerList class closely yet, but this implies that it stores objects and events in pairs? The list contains an object and the next entry in the list contains which type of event the object is registered for? So the length of the list will always be an even number? Or is that backwards? *looks at it again*

JJCoolBa at 2007-7-21 20:20:18 > top of Java-index,Java Essentials,New To Java...
# 23

> I haven't looked at the EventListenerList class closely yet, but this implies that it stores objects and events in pairs?

That's right. It stores: class, listener, class, listener, ...class, listener.

> So the length of the list will always be an even number?

Yes.

The reason why it does this is so that you can store different listeners in the same

instance of EventListenerList, so that one doesn't have to instantiate this class

many times because a component maintains lists of ComponentListeners,

ActionListeners, KeyListeners, etc...

DrLaszloJamfa at 2007-7-21 20:20:18 > top of Java-index,Java Essentials,New To Java...
# 24

One more question..

public void addModelListener(ModelListener l) {

ll.add(ModelListener.class, l);

}

I'm not too familiar with the <interface>.class notation being used here.. Is the <interface>.class a reference to the class that is implementing the interface? If that's the case, what is being stored into the list? Not a reference to an instance of a class, but just the class definition itself? Which aspect of the class?

>>The reason why it does this is so that you can store different listeners in the same

>>instance of EventListenerList, so that one doesn't have to instantiate this class

>>many times because a component maintains lists of ComponentListeners,

>>ActionListeners, KeyListeners, etc...

*nod* That's sorta what I figured. ^.^

JJCoolBa at 2007-7-21 20:20:18 > top of Java-index,Java Essentials,New To Java...
# 25

> I'm not too familiar with the <interface>.class

> notation being used here.. Is the <interface>.class

> a reference to the class that is implementing the

> interface?

No, ModelListener.class refers to the java.lang.Class object associated

with interface ModelListener. Perhaps they should have used the syntax

ModelListener.type, but they didn't...

> If that's the case, what is being stored

> into the list? Not a reference to an instance of a

> class, but just the class definition itself? Which

> aspect of the class?

Associated with every type (including every class and interface) is an

instance of java.lang.Class. This class is useful in reflection, but that's

not why its used here. It's used so that the EventListenerList can

simultaneously maintain several different listeners lists. Suppose you

want your class to maintain a list of ActionListeners and a list of

FocusListeners. A single EventListenerList can do that by storing pairs:

either ActionListener.class and an action listener, or FocusListener.class

and a focus listener. Now suppose your class X implements both

ActionListener and FocusListener, but you add it only as a FocusListener.

This guarantees that if you are raising an action event, you will not invoke

X's actionPerformed method, even though it is an ActionListener, and it

is on the EventListenerList.

DrLaszloJamfa at 2007-7-21 20:20:18 > top of Java-index,Java Essentials,New To Java...
# 26
What about the Observer interface and Observable class provided by java.util? I posted a question about it in the other thread?
Rob-UKa at 2007-7-21 20:20:18 > top of Java-index,Java Essentials,New To Java...
# 27

> What about the Observer interface and Observable class provided by java.util?

You can use java.util. Observer/Observable, too, but there's nothing

special about them. If you open up src.zip you'll realize there's not

a lot to them, and I don't think they're used anywhere else that I've seen

in the API.

I guess I'm partial to EventListenerList, but there's nothing remarkable about it

either. It has a certain amount of thread safety to it, if that matters...

In the end, it wouldn't be hard to roll up your own code to support the observer

pattern directly, either.

DrLaszloJamfa at 2007-7-21 20:20:18 > top of Java-index,Java Essentials,New To Java...
# 28
ok. Thanks Dr! You've been very helpful! ^.^ I'll start another application and try to incorporate this into it. I'll probably be back this weekend with more questions.
JJCoolBa at 2007-7-21 20:20:18 > top of Java-index,Java Essentials,New To Java...
# 29

When using the Observer/Observable method, how would I get the view to pull the initial data from the model?

Edit: I have found a simple way of doing it. Overriding the addObserver(Observer o) method and fowarding the call to the superclass but also adding a setChanged() and a notifyObservers() call to the method. Everytime a new observer is added (such as when a view is created) the data is automatically sent to the view.

public void addObserver(Observer o) {

super.addObserver(o);

setChanged();

notifyObservers();

}

Rob-UKa at 2007-7-21 20:20:18 > top of Java-index,Java Essentials,New To Java...
# 30

... or you could get the view to pull the initial data from the model in the view's setModel method:

public void setModel(Model model) {

this.model = model;

...pull !...

}

DrLaszloJamfa at 2007-7-21 20:20:23 > top of Java-index,Java Essentials,New To Java...
# 31
What would you do for the update() method (when using an observer) in your case to avoid repeating the code that populates the field?
Rob-UKa at 2007-7-21 20:20:23 > top of Java-index,Java Essentials,New To Java...
# 32

You could *push* information about the change in the model. If you are using

java.util.Observer:

public void update(Observable o, Object arg) {

MyHint hint = (MyHint) arg;

... use information in hint...

}

Usually, to just get something up and running, I don't get that fancy. Just

have the view assume nothing and start from scratch. You can also

write slicker code later.

DrLaszloJamfa at 2007-7-21 20:20:23 > top of Java-index,Java Essentials,New To Java...