next up previous contents index
Next: Singleton Pattern Up: Grundlagen Patterns Previous: Observer Pattern   Contents   Index


MVC Pattern

Figure 4.2: Model-View-Control-Pattern
Image C:
<BR>
images/umlMVC.jpg

Das Kürzel MVC steht für Model-View-Control. Das MVC-Pattern ist eigentlich relativ einfach. Es besagt, dass ein Programm in drei unterschiedliche Teile aufgeteilt ist. (siehe Abb.4.2)
Der Model-Teil beinhaltet dabei die Daten bzw. den Datenzugriff. Hier könnten sich klassische Objekte eines objektorientierten Programms befinden oder auch ein Datenbankzugriff oder jede andere Art von Datenverwaltung.
Des Weiteren gibt es noch den View-Abschnitt. Hier befinden sich alle Ansichten des Programms. Diese zeigen normalerweise die Daten des Models an und sind komplett unabhängig von den Daten implementiert.
Der dritte Teil des Patterns ist der Control-Teil. Dieser beinhaltet alle Kontrollmöglichkeiten, mit welchen ein Benutzer das Programm steuern kann. Auch dieser Teil ist normalerweise komplett unabhängig von den anderen Teilen.

In manchen Programmiersprachen bzw. Anwendungen ist man gezwungen den View-, sowie den Controlteil in einer Struktur unterzubringen. Dieses Pattern wird dann als Document-View Modell bezeichnet.

Die einzelnen Teilbereiche besitzen in einer Umsetzung des MVC-Patterns meistens nur Referenzen auf die anderen Teilbereiche. Dabei werden nur die definierten Zugriffsmethoden verwendet. Es ist also beispielsweise nicht möglich von einer View-Klasse direkt auf Objekte der Model-Klasse zuzugreifen.

Im folgenden Beispiel wird ein Programm vorgestellt, welches nicht nur ein MVC-Entwurfsmuster implementiert, sondern gleichzeitig auch noch ein Observer-Pattern verwendet. Diese Vermischung der beiden Entwurfsmuster kommt sehr häufig vor, da sie gut zusammen passen. Dabei sind die beiden so verknüpft, dass es sich bei den View-Klassen um die Observerklassen des Observer-Patterns handelt und die Model-Klasse die Subject-Klasse des Patterns repräsentiert.


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

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;

interface View{
	//Muss von allen Views implementiert werden
	public void refresh();
}

class RealView extends JFrame implements View{
	//Id des Fensters
	private int id;
	
	//Referenz auf das Model
	private Model model;
	
	//JTextField des Fensters
	private JTextField txt;
	
	//Konstruktor
	public RealView(int id, Model model){
		this.id = id;
		this.model = model;
		
		setTitle("View " + id);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		txt = new JTextField("");
		getContentPane().add(txt);
		
		refresh();
		
		setLocation(250, 60 * id);
		pack();
		setVisible(true);
	}
	
	/*
	 * Wird ausgeführt, wenn sich etwas an den
	 * Daten im Model ändert
	 */
	public void refresh(){
		txt.setText(
			"View " + id + ": " + 
			model.getValue());
	}
}

class ButtonView extends JFrame{	
	public ButtonView(Model model){		
		//Stellt die Eigenschaften des Fensters ein
		setTitle("ButtonView");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		//Fügt die Controlklasse zu dem Button hinzu
		JButton btn = new JButton("Increment");
		btn.addActionListener(new Control(model));
		getContentPane().add(btn);
		
		//Zeigt das Fenster an
		setLocation(100,100);
		pack();
		setVisible(true);		
	}
}

class Control implements ActionListener{
	//Referenz auf das Model
	private Model model;
	
	//Konstruktor
	public Control(Model model){
		this.model = model;
	}
	
	//Wird ausgeführt, wenn man den Button anklickt
	public void actionPerformed(ActionEvent evt){
		model.incValue();
	}
}

class Model{
	//Alle angemeldeten Views
	private ArrayList views;
	
	//Daten
	private int curValue;
	
	//Konstruktor
	public Model(){
		views = new ArrayList();
		curValue = 0;
	}
	
	//Fügt eine neue View hinzu
	public void addView(View view){
		views.add(view);
		view.refresh();
	}
	
	//Entfernt eine View
	public void removeView(View view){
		views.remove(view);
	}
	
	//Benachrichtigt alle Views
	public void notifyViews(){
		for(View v : views){
			v.refresh();
		}
	}
	
	//Inkrementiert die Daten
	public void incValue(){
		curValue++;
		notifyViews();
	}
	
	//Gibt die Daten zurück
	public int getValue(){
		return curValue;
	}
}

public class MVCPattern {
	public static void main(String[] args){
		/*
		 * Erstellt das Model, in welchem die Daten,
		 * sowie die Views verwaltet werden.
		 */
		Model model = new Model();
		
		//Die Views, welche die Daten anzeigen
		RealView view1 = new RealView(1, model);
		RealView view2 = new RealView(2, model);
		
		//Die Views tragen sich bei dem Model ein
		model.addView(view1);
		model.addView(view2);
		
		//Die View zur Bedienung des Programms
		new ButtonView(model);
	}
}

Der hier gezeigte Quellcode enthält eine Klasse Model. Diese Klasse repräsentiert die Model-Klasse des MVC-Patterns und gleichzeitig die Subject-Klasse des Observer-Patterns. Sie enthält also alle Daten bzw. Referenzen auf Daten und verwaltet eine Liste mit allen Observern. Des Weiteren gibt es die Klasse Control, welche natürlich den Control-Bereich des MVC-Patterns darstellt. Über solch eine Klasse können beispielsweise Änderungen an dem Model durchgeführt werden. Diese sind jedoch nur über Zugriffsmethoden möglich, welche die Model-Klasse implementiert. Dann wären da noch die View-Klassen ButtonView und RealView. Diese implementieren die Schnittstelle View, welche mit der Observer-Schnittstelle des Observer-Patterns gleichzusetzen ist. Da sie diese Schnittstelle implementieren, können sie sich bei dem Model eintragen und werden über Datenänderungen benachrichtigt. Die RealView hat damit dann die Möglichkeit die Daten des Models aktualisiert darzustellen, sobald sie sich ändern. Die ButtonView enthält nur einen Button, welcher die Control-Klasse verwendet um im Model die Daten zu verändern.

Man sieht also, dass alle Klassen zwar in Beziehungen stehen aber trotz allem unabhängig voneinander implementiert werden. Dadurch hat man die Möglichkeit das Programm später durch zusätzliche Controls oder Views zu erweitern, ohne die Integrität des Programms zu beeinflussen.


next up previous contents index
Next: Singleton Pattern Up: Grundlagen Patterns Previous: Observer Pattern   Contents   Index
Rainer Friesen, Markus Stollenwerk und Daniel Valentin, 2007-03-06