# Model View Controller - Beispielimplementation



## Clip (25. Nov 2005)

Hallo,

ich möchte eine Applikation nach dem MVC Prinzip aufbauen. Ich habe mir die Theorie dazu durchgelesen, ich komme allerdings an dem Punkt an den ein Observer ins Spiel kommt nicht mehr weiter. Ich habe versucht mal eine kleine Beispielimplementation zu scheiben um mir selbst das Prinzip zu verdeutlichen. Wie gesagt, ich denke es hapert noch an so manch einer Stelle.
In Dem Beispiel gibt es einen Button und eine Checkbox. Ich möchte, dass wenn der Button gedrückt wird die Checkbox ihren Zustand ändert. Und zwar über das Model, wobei die View im Model nicht bekannt sein soll (deswegen Observer).
Unsicher bin ich mir wie gesagt bei dem Observer kram, und ob ich die Instantierung der Klassen, insbesondere des Controllers richtig gemacht habe. 
Ich würde mich freuen wenn mir jemand helfen könnte. Wenn das Beispiel steht wäre es ja evtl. was für die FAQs, da hätte ich zumindest gerne soetwas in der Art gefunden 

Danke!

Applikation

```
package foo.MVC;

public class MyApplication {

	public static void main(String[] args) {
		MyModel model = new MyModel();
		MyView view = new MyView(model);
		view.setVisible(true);
	}
}
```

View:

```
package foo.MVC;

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JButton;
import javax.swing.JCheckBox;

public class MyView extends JFrame implements Observer{

	private JPanel jPanel = null;
	public JButton jButton = null;
	public JCheckBox jCheckBox = null;
	private MyController controller;
	

	public MyView(MyModel model) {
		super();
		controller = new MyController(this, model);
		initialize();
	}

	private void initialize() {
		this.setSize(219, 128);
		this.setContentPane(getJPanel());
		this.setTitle("Titel");
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE );
	}

	private JPanel getJPanel() {
		if (jPanel == null) {
			jPanel = new JPanel();
			jPanel.setLayout(new BorderLayout());
			jPanel.add(getJButton(), java.awt.BorderLayout.CENTER);
			jPanel.add(getJCheckBox(), java.awt.BorderLayout.SOUTH);
		}
		return jPanel;
	}

	private JButton getJButton() {
		if (jButton == null) {
			jButton = new JButton();
			jButton.setText("OK");
			jButton.addActionListener(controller);
			
		}
		return jButton;
	}

	private JCheckBox getJCheckBox() {
		if (jCheckBox == null) {
			jCheckBox = new JCheckBox();
		}
		return jCheckBox;
	}

	public void update(Observable arg0, Object arg1) {
		///??? was genau soll hire hin ???		
	}

}  //  @jve:decl-index=0:visual-constraint="10,10"
```

Model:

```
package foo.MVC;

import java.util.Observable;

public class MyModel extends Observable{	
	boolean myValue = true;
	
	public MyModel(){
		// hier sollte im View die Checkbox gemäß myValue eingestellt werden
	}
	
	public void setMyValue(boolean myValue){
		this.myValue = myValue;
		// hier sollte im View die Checkbox gemäß myValue eingestellt werden
		// notifyObservers(???);
	}	
	
	public boolean getMyValue(){
		return myValue;
	}
}
```

Controller:

```
package foo.MVC;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class MyController implements ActionListener{
	private MyView view = null;
	private MyModel model = null;

	public MyController(MyView view, MyModel model ){
		this.view = view;
		this.model = model;
	}
	
	public void actionPerformed(ActionEvent e) {
	    Object which = e.getSource();
	    if (which == view.jButton) {
	    	model.setMyValue(!model.getMyValue());
		}
    }		
}
```


----------



## pogo (25. Nov 2005)

da gibt es so etwas. ist halt unter design pattern 

Designpattern


----------



## Clip (25. Nov 2005)

ohh   

Der Vollständigkeit halber die Klassen nach der Vorlage aus den FAQs:

Applikation:

```
package foo.MVC;

public class MyApplication {

	public static void main(String[] args) {
		MyController controller = new MyController();		
	}
}
```

View:

```
package foo.MVC;

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JButton;
import javax.swing.JCheckBox;

public class MyView extends JFrame implements Observer{

	private JPanel jPanel = null;
	public JButton jButton = null;
	public JCheckBox jCheckBox = null;
	private MyController controller;
	

	public MyView(MyController controller) {
		super("WindoController");
		this.controller = controller;
		initialize();
		this.setVisible(true);
	}

	private void initialize() {
		this.setSize(219, 128);
		this.setContentPane(getJPanel());
		this.setTitle("Titel");
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE );
	}

	private JPanel getJPanel() {
		if (jPanel == null) {
			jPanel = new JPanel();
			jPanel.setLayout(new BorderLayout());
			jPanel.add(getJButton(), java.awt.BorderLayout.CENTER);
			jPanel.add(getJCheckBox(), java.awt.BorderLayout.SOUTH);
		}
		return jPanel;
	}

	private JButton getJButton() {
		if (jButton == null) {
			jButton = new JButton();
			jButton.setText("OK");
			jButton.addActionListener(controller);			
		}
		return jButton;
	}

	private JCheckBox getJCheckBox() {
		if (jCheckBox == null) {
			jCheckBox = new JCheckBox();
			jCheckBox.setSelected(true);
		}
		return jCheckBox;
	}

	public void update(Observable arg0, Object arg1) {
		MyModel model = (MyModel) arg1;
		jCheckBox.setSelected(model.getMyValue());
	}

}  //  @jve:decl-index=0:visual-constraint="10,10"
```

Model:

```
package foo.MVC;


public class MyModel {	
	boolean myValue = true;
	
	public void setMyValue(boolean myValue){
		this.myValue = myValue;
	}	
	
	public boolean getMyValue(){
		return myValue;
	}
}
```

Controll:

```
package foo.MVC;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observable;

public class MyController extends Observable implements ActionListener {
	private MyView view = null;
	private MyModel model = null;

	public MyController(){
		view = new MyView(this);
		model = new MyModel();
		addObserver(view);
	}
	
	public void actionPerformed(ActionEvent e) {
	    Object which = e.getSource();
	    if (which == view.jButton) {
	    	model.setMyValue(!model.getMyValue());
	    	setChanged(); 
	    	notifyObservers(model); 
		}
    }		
}
```


----------



## Jörg (28. Nov 2005)

view:

```
public void update(Observable arg0, Object arg1) { 
      ///??? was genau soll hire hin ???       
      // so etwas:
      boolean value = model.getValue(); // oder:
      boolean value = (ModelValue) arg1;
      checkbox.setValue(value); //bzw.
      checkbox.setSelected(value);
   }
```

model:

```
public MyModel(){ 
      // hier sollte im View die Checkbox gemäß myValue eingestellt werden 
      // noe
   } 
    
   public void setMyValue(boolean myValue){ 
      this.myValue = myValue; 
      // hier sollte im View die Checkbox gemäß myValue eingestellt werden 
      // genau:
      notifyObservers(myValue); 
      // macht das ueber die update() methode ... 
   }
```


----------



## Clip (29. Nov 2005)

Danke Jörg.
Eine Frage zu Deinem Code.
In Deiner Ausführung führst Du die Methode  "notifyObservers()" im Model aus. Ist es nicht besser dies im Controller zu tun um eine bessere Trennung zwischen View und Model zu haben?
Und in Deinem View tust Du folgendes:

```
boolean value = model.getValue(); // oder:
      boolean value = (ModelValue) arg1;
```
Woher kennt die View Schicht denn das Model? Dan muss das Model doch als Referenz im View bekannt sein, oder?
Wie kann ich mit Deiner Methode im View un der Funktion "update" unterscheiden welcher Wert geupdatet wurde?
 :?:


----------



## Jörg (29. Nov 2005)

tja also da gibt es jetzt (IMHO) verschiedene Ansaetze.  
Im eigentlichen MVC weiss erstmal nur das Model vom View
nichts. Du kannst die beiden noch mehr voneinander trennen, 
aber irgendwann kommst du deinem Ziel nicht mehr hinterher...



> notifyObservers() in den Controller legen


ist zb noch ne gute Idee, aber nicht wirklich noetig, wenn du
nur eine dedizierte Applikation bauen willst.



> Woher kennt die View Schicht denn das Model?


Wie oben gesagt, kann das schon der Fall sein, schliesslich
soll der View ja die Daten des Models repraesentieren. Natuerlich
kannst das alles auch in den Controller legen. 

Das war halt meine Loesung und dazu kannst du dann das arg1
als ValueObject realisieren, welches den Namen der Property
haelt, sowie den alten und neuen Wert...

Kuck dir vielleicht auch mal den PropertyChangeSupport an!
Evtl interessieren dich auch die slides zum binding auf jgoodies.com


----------

