MVC problem

I have tried to implement the Model View Controller pattern in my project but I have noticed that it has caused a double aggregation between my GUI classes (views) and my controllers. (see the class diagram). I'm basically asking, is this a bad thing and how do I solve it?

I need the controller to keep a reference to the view so that it can use the accessor methods on the view to retrieve user input and the mutator methods to propagate changes from the model.

However, I need the view to keep a reference to the controller so that it knows where to send information about actions performed on the gui such as button presses.

Class Diagram:

http://renhelp.laeubi-soft.de/images/java.jpg

publicclass QuestionController{

private QuestionDB model;

private EditQuestion view;

public QuestionController(){

showGUI();

}

publicvoid showGUI(){

view =new EditQuestion(this);

view.setVisible(true);

}

publicvoid updateQuestion(){

// Get information from view

int selected = view.getSelectedQuestion();

String question = view.getQuestionText();

ArrayList<String> answers = view.getAnswers();

// Update the model

Question q = model.getQuestion(selected);

q.setQuestionText(question);

q.setAnswers(answers);

}

}

publicclass EditQuestion{

private QuestionController qc;

public EditQuestion(QuestionController qc){

// Initialise GUI components

initComponents();

this.qc = qc;

}

/* GUI Code here */

//ComboBox with a list of questions

//TextArea to hold the question string

//4 TextFields to hold answers

//Button to save changes

/* Action Listeners */

privatevoid updateQuestionButtonActionPerformed(ActionEvent evt){

// Tell controller to update the model

qc.updateQuestion();

}

/* Accessor & Mutators */

publicint getSelectedQuestion(){}//Returns the index of selected item in combo box

public String getQuestionText(){}//Returns the contents of the textarea

publicvoid setQuestionText(String str){}//Sets the text in the textarea

public ArrayList<String> getAnswers(){}//Gets the answers from the textfields

publicvoid setAnswers(ArrayList<String> ans){}//Sets the answers in the textfields

}

Let me know if anything isn't clear.

Thanks

[4488 byte] By [Rob-UKa] at [2007-11-27 2:08:49]
# 1

> However, I need the view to keep a reference to the

> controller so that it knows where to send information

> about actions performed on the gui such as button

> presses.

No you don't. Well you do if your View is acting as the listener, but you should make the controller listen to the components instead. The View shouldn't worry about those.

-Kayaman-a at 2007-7-12 1:58:33 > top of Java-index,Java Essentials,Java Programming...
# 2
So what's the best way to make the controller listen for the GUI events. How do I go about registering the controller to listen on a paticular view if the controller is controlling several views?Thanks
Rob-UKa at 2007-7-12 1:58:33 > top of Java-index,Java Essentials,Java Programming...
# 3

You will need to have the two referring each other no matter what

method you use. I use the following pattern to do this I hope its useful to you.

public interface View{

public void setController(Controller con);

//other methods

}

public class ViewImpl implements View{

Controller con;

public ViewImpl(){

}

public void setController(Controller con){

this.con = con;

}

//other methods

}

public class Controller{

View view;

public Controller(View view){

this.view = view;

view.setController(this);

}

}

WirajRa at 2007-7-12 1:58:33 > top of Java-index,Java Essentials,Java Programming...
# 4

> You will need to have the two referring each other no

> matter what method you use.

That's incorrect, the View only needs to reference the model to get the data it is supposed to show. It doesn't need the controller.

As for OP's question, the code you showed doesn't even involve events. The method for an ActionListener is actionPerformed(ActionEvent e), nothing else. You can make your controller implement ActionListener and add it as a listener to your GUI components.

-Kayaman-a at 2007-7-12 1:58:33 > top of Java-index,Java Essentials,Java Programming...
# 5
So actionPerformed() will be called when any button is pressed on the gui if I register all the buttons with the controller class. How do I determine which button was pressed?I can use internal classes as an alternative but is the above possible?
Rob-UKa at 2007-7-12 1:58:33 > top of Java-index,Java Essentials,Java Programming...
# 6

> So actionPerformed() will be called when any button

> is pressed on the gui if I register all the buttons

> with the controller class. How do I determine which

> button was pressed?

Use the set and getActionCommand methods. You set a String to the button's action command, which is passed along with the ActionEvent.

hunter9000a at 2007-7-12 1:58:33 > top of Java-index,Java Essentials,Java Programming...
# 7

> > You will need to have the two referring each other

> no

> > matter what method you use.

>

> That's incorrect, the View only needs to reference

> the model to get the data it is supposed to show. It

> doesn't need the controller.

You mean to tell me that the View does not need to reference the Controller? Then

how are you going to register an instance of the controller as an ActionListener with

UI components in the View implementation.

WirajRa at 2007-7-12 1:58:33 > top of Java-index,Java Essentials,Java Programming...
# 8

> You mean to tell me that the View does not need to

> reference the Controller? Then

> how are you going to register an instance of the

> controller as an ActionListener with

> UI components in the View implementation.

You're right of course, but the controller reference is only needed temporarily to set up the listeners. I think Kayaman's point is that you don't use the controller reference to pass parameters from the view, you let the controller handle swing events itself. You wouldn't need to keep a reference to the controller after initialization that way.

hunter9000a at 2007-7-12 1:58:33 > top of Java-index,Java Essentials,Java Programming...
# 9

Either way the View implementation should receive an instance of the

Controller and that抯 my point and I think that抯 what the OP is asking.

By the way implementing ActionListener in the controller may result in a ClassNotFoundException

in some Linux environments where X is not installed. Therefore your solution won抰 be fully independent.

WirajRa at 2007-7-12 1:58:33 > top of Java-index,Java Essentials,Java Programming...
# 10

> You mean to tell me that the View does not need to

> reference the Controller?

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.

> Then how are you going to register an instance of the

> controller as an ActionListener with

> UI components in the View implementation.

That depends, it can be as easy as

view.addActionListener(myController);

view.addActionListener(this);

view.getComponent().addActionListener(myController);

etc. etc.

In the purest form, the view shouldn't know pretty much anything, except how to display data, i.e. have a reference to a model.

-Kayaman-a at 2007-7-12 1:58:33 > top of Java-index,Java Essentials,Java Programming...
# 11

This is the same as passing the Controller you are just being less formal about it.

You are just filtering out the ActionListerer interface.

If you are worried about polymorphism (i.e. ability to plug in different controllers)

then you should reference the controller with a custom interface type. IMO Using

awt/swing packages in Controller code is not a good solution.

WirajRa at 2007-7-12 1:58:33 > top of Java-index,Java Essentials,Java Programming...
# 12

At the moment in my MVC design, the view knows nothing which is the way it should be. However the view also don't get it's data from the model directly, it gets it via the controller. The controller fetches some data from the model and calls mutators on the view to display it.

I've looked at the Observer/Observable classes but I can't figure out exactly how they work. EG: I create a view which takes the model as a parameter and then adds itself as an observer to the model. If I understood correctly, the view will only recieve data from the model when the model has changed, how does the view get the initial information from the model?

I also understand that the update method has to be written in the view, does this just call methods on the model and then populate the components in the view with the information?

Thanks

Rob-UKa at 2007-7-12 1:58:33 > top of Java-index,Java Essentials,Java Programming...