Hallo Java-Freunde!
Ich versuche mich nun gerade, in das Prinzip des Model-View-Control Pattern einzuarbeiten. Dazu habe ich nun eine kleine Anwendung geschrieben. Ich habe sie ziemlich klein gehalten, weshalb das Anwenden vom MVC-Prinzip wohl etwas überdimensioniert ist, aber es geht mir ja darum, das Prinzip zu verstehen.
Die Anwendung speichert in einem MemoryModel einen aktuellen Wert, der als Speicher dient, und einen Wert für das Intervall, mit dem man den Speicher erhöhen und verringern kann.
Als View-Komponente habe ich einen MemoryFrame erstellt, der als Hauptfenster dienen soll. Er bietet ein Label, in dem der aktuelle Wert des Models steht, und zwei Schaltflächen zum erhöhen und verringern des Wertes. DIe Schritte, um die der Wert erhöht wird, soll dabei in der Größe des im Model gespeicherten Intervals erfolgen. Zwischen den beiden Komponenten gibt es einen MemoryController, der als Vermittler zwischen beiden dienen soll. Grafisch sieht das ganze nun so aus:
Wenn man jetzt auf den zusätzlich vorhandenen, dritten Button klickt, so soll sich ein neuer, selbst erstellter Dialog öffnen, mit dem man die Schrittefolge, in der sich der Wert ändert, ändern kann. Er sieht so aus:
Ich poste nun hier einmal meinen Quellcode:
Das wäre nun also der Teil, der sozusagen das Hauptfenster darstellt. Jetzt habe ich für den Dialog ebenfalls ein Model, ein View und ein Controller erstellt. Man könnte zwar auch einen einfachen Dialog über das JOptionPane erstellen, aber ich will das Prinzip ja verstehen, mit dem man an ein MVC erstelltes Projekt angeht. Hier also der Code, der für den Dialog zuständig ist:
Das war jetzt ziemlich viel zu lesen, aber vll. ist ja noch jemand hier unten angekommen
Meine Frage ist nun: Habe ich das Prinzip des MVC halbwegs korrekt angewendet?
Sollte der Controller immer eine Instanz auf das Model UND den View als Attribut besitzen? Wenn man in den Code schaut, dann sieht man ja, dass ich in dem MemoryView einen neuen ChangeIntervallController erstelle, um den Dialog zum Ändern des Intervals anzuzeigen. Um den Dialog auch hinterher modal verwenden zu können, muss ich die Referenz auf das Vater-Fenster ja irgendwie an den Dialog übergeben können.
Habe ich das so ungefähr richtig gemacht? Der MemoryCOntroller kann ja die Referenz auf die View-Komponente zurückgeben. Deshalb habe ich dem ChangeIntervalController über den Konstruktor eine Instanz des Vater-Kontrollers mit übergeben.
Kann man das so machen?
Ich hoffe, dass mir jemand ein wenig kritik und anregung geben kann.
Danke schonmal
Ich versuche mich nun gerade, in das Prinzip des Model-View-Control Pattern einzuarbeiten. Dazu habe ich nun eine kleine Anwendung geschrieben. Ich habe sie ziemlich klein gehalten, weshalb das Anwenden vom MVC-Prinzip wohl etwas überdimensioniert ist, aber es geht mir ja darum, das Prinzip zu verstehen.
Die Anwendung speichert in einem MemoryModel einen aktuellen Wert, der als Speicher dient, und einen Wert für das Intervall, mit dem man den Speicher erhöhen und verringern kann.
Als View-Komponente habe ich einen MemoryFrame erstellt, der als Hauptfenster dienen soll. Er bietet ein Label, in dem der aktuelle Wert des Models steht, und zwei Schaltflächen zum erhöhen und verringern des Wertes. DIe Schritte, um die der Wert erhöht wird, soll dabei in der Größe des im Model gespeicherten Intervals erfolgen. Zwischen den beiden Komponenten gibt es einen MemoryController, der als Vermittler zwischen beiden dienen soll. Grafisch sieht das ganze nun so aus:

Wenn man jetzt auf den zusätzlich vorhandenen, dritten Button klickt, so soll sich ein neuer, selbst erstellter Dialog öffnen, mit dem man die Schrittefolge, in der sich der Wert ändert, ändern kann. Er sieht so aus:

Ich poste nun hier einmal meinen Quellcode:
Code:
public class MemoryModel extends Observable {
/** Das Intervall, in dem <code>value</code> erhöht/verringert wird */
private int interval;
/** Der aktuelle Wert */
private int value;
/**
* Erzeugt ein neues MemoryModel
* Der Standardwert für <code>interval</code> ist <code>1</code>,
* der Standardwert für <code>value</code> ist <code>0</code>
*/
public MemoryModel() {
this.interval = 1;
this.value = 0;
}
/**
* Erhöht <code>value</code> um den Wert <code>interval</code>
*/
public void increment() {
this.value = this.value + this.interval;
setChanged();
notifyObservers();
}
/**
* Verringert <code>value</code> um den Wert <code>interval</code>
*/
public void decrement() {
this.value = this.value - this.interval;
setChanged();
notifyObservers();
}
/**
* Gibt den aktuell gespeicherten Wert zurück
* @return aktueller Wert
*/
public int getValue() {
return this.value;
}
public void setInterval(int interval) {
this.interval = interval;
}
}
Code:
public class MemoryFrame extends JFrame implements Observer {
/** Die Anzeige für den aktuellen Wert des Models */
private JLabel valueLabel;
/** Der verwendete MemoryController */
private MemoryController controller;
/** Das verwendete MemoryModel, das observiert wird */
private MemoryModel model;
/**
* Erstellt einen neuen MemoryFrame
*/
public MemoryFrame(MemoryController controller) {
this.controller = controller;
this.model = controller.getModel();
this.model.addObserver(this);
createUI();
}
/**
* Erstellt die GUI des Frames
*/
public void createUI() {
JPanel pane = new JPanel();
this.valueLabel = new JLabel("" + model.getValue());
// Button zum Erhöhen des Wertes
JButton b1 = new JButton("Erhöhen");
b1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
controller.increment();
}
});
// Button zum verringern des Wertes
JButton b2 = new JButton("Verringern");
b2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
controller.decrement();
}
});
// Button zum ändern der Intervalgröße
JButton b3 = new JButton("Interval verändern");
b3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
ChangeIntervalController intController = new ChangeIntervalController(controller);
// Wurde der neue Wert auch bestätigt oder das Fenster nur geschlossen?
if (intController.getModel().isConfirmed()) {
controller.setInterval(intController.getModel().getInterval());
}
}
});
pane.add(this.valueLabel);
pane.add(b1);
pane.add(b2);
pane.add(b3);
add(pane);
setTitle("Verrgingern/Vergrößern des gespeicherten Wertes");
setSize(800, 100);
setVisible(true);
}
/**
* Sorgt für ein Update des Labels, falls sich der Wert des Models geändert hat.
* @param o das observierte Objekt
* @param arg Optionales Datenobjekt
*/
public void update(Observable o, Object arg) {
this.valueLabel.setText("" + ((MemoryModel)o).getValue() );
}
}
Code:
public class MemoryController {
/** Das MemoryModel */
private MemoryModel model;
/** Instanz des Frames */
private MemoryFrame frame;
public MemoryController() {
this.model = new MemoryModel();
frame = new MemoryFrame(this);
}
/**
* Gibt das Model diesen Controllers zurück
* @return das Model
*/
public MemoryModel getModel() {
return this.model;
}
/**
* Gibt die Instanz des Frames zurück
* @return der Frame
*/
public MemoryFrame getFrame() {
return this.frame;
}
/**
* Lässt das Model seinen Wert erhöhen
*/
public void increment() {
this.model.increment();
}
/** Lässt das Model seinen Wert verringern */
public void decrement() {
this.model.decrement();
}
/**
* Ändert den Interval des Models
* @param interval
*/
public void setInterval(int interval) {
this.model.setInterval(interval);
}
}
Das wäre nun also der Teil, der sozusagen das Hauptfenster darstellt. Jetzt habe ich für den Dialog ebenfalls ein Model, ein View und ein Controller erstellt. Man könnte zwar auch einen einfachen Dialog über das JOptionPane erstellen, aber ich will das Prinzip ja verstehen, mit dem man an ein MVC erstelltes Projekt angeht. Hier also der Code, der für den Dialog zuständig ist:
Code:
public class ChangeIntervalModel extends Observable {
/** Der Wert, auf den das Interval des MemoryModels gesetzt werden soll */
private int newInterval;
/** Zeigt an, ob dieses Intervall wirklick übernommen werden soll */
private boolean confirmed;
/**
* Setzt den Wert des neuen Intervals
*/
public void setInterval(int interval) {
this.newInterval = interval;
setChanged();
notifyObservers();
}
/**
* Gibt den Wert des neuen Intervals zurück
* @return das neue Interval
*/
public int getInterval() {
return this.newInterval;
}
/**
* Erhöht <code>value</code> um den Wert <code>interval</code>
*/
public void increment() {
this.newInterval++;
setChanged();
notifyObservers();
}
/**
* Verringert <code>value</code> um den Wert <code>interval</code>
*/
public void decrement() {
this.newInterval--;
setChanged();
notifyObservers();
}
/**
* Setzt <code>confirmed</code> auf <code>true</code>
*/
public void confirm() {
this.confirmed = true;
}
/**
* Gibt zurück, ob dieses Intervall wirklich übernommen werden soll
* @return <code>true</code>, falls es übernommen werden soll
*/
public boolean isConfirmed() {
return this.confirmed;
}
}
Code:
public class ChangeIntervalDialog extends JDialog implements Observer {
/** Der Controller zum Wechsel des Intervals */
private ChangeIntervalController controller;
/** Das Model des Interval-Wechslers */
private ChangeIntervalModel model;
/** Label für das neue Interval */
private JLabel newIntervalLabel;
/**
* Erstellt einen neuen Dialog zum Ändern des Intervals
* @param frame Vater-Frame
* @param modal
* @param controller der verwendete Controller
*/
public ChangeIntervalDialog(JFrame frame, boolean modal, ChangeIntervalController controller) {
super(frame, modal);
this.controller = controller;
this.model = controller.getModel();
this.model.addObserver(this);
createUI();
}
/**
* Erstellt die Oberfläche des Interval-Wechslers
*/
public void createUI() {
JPanel pane = new JPanel();
newIntervalLabel = new JLabel("Geplantes Interval: " + this.model.getInterval());
// Button zum Erhöhen des neuen Intervals
JButton b1 = new JButton("Erhöhen");
b1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
controller.increment();
}
});
// Button zum Verringern des neuen Intervals
JButton b2 = new JButton("Verringern");
b2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
controller.decrement();
}
});
JButton b3 = new JButton("Wert übernehmen");
b3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
controller.confirm();
setVisible(false);
}
});
pane.add(newIntervalLabel);
pane.add(b1);
pane.add(b2);
pane.add(b3);
add(pane);
setSize(500, 200);
setVisible(true);
}
/**
* Ändert das Label auf den Wert des geplanten, neuen Intervals
* @param o das observierte ChangeIntervalModel
* @param arg optionales Datenobjekt
*/
public void update(Observable o, Object arg) {
this.newIntervalLabel.setText("Geplantes Interval: " + ((ChangeIntervalModel)o).getInterval());
}
}
Code:
public class ChangeIntervalController {
/** Das Model für den Interval-Wechsler */
private ChangeIntervalModel model;
/** Instanz des Hauptframes / Ermittelt durch den "Vater-Controller" */
private JFrame mainframe;
/**
* Erstellt einen neuen ChangeIntervalController
*/
public ChangeIntervalController(MemoryController controller) {
this.model = new ChangeIntervalModel();
mainframe = controller.getFrame();
ChangeIntervalDialog diag = new ChangeIntervalDialog(mainframe, true, this);
}
/**
* Gibt das verwendete Model zurück
* @return das Model
*/
public ChangeIntervalModel getModel() {
return this.model;
}
/**
* Erhöht den Wert des geplanten, neuen Intervals
*/
public void increment() {
this.model.increment();
}
/**
* Verringert den Wert des geplanten, neuen Intervals
*/
public void decrement() {
this.model.decrement();
}
public void confirm() {
this.model.confirm();
}
}
Das war jetzt ziemlich viel zu lesen, aber vll. ist ja noch jemand hier unten angekommen
Meine Frage ist nun: Habe ich das Prinzip des MVC halbwegs korrekt angewendet?
Sollte der Controller immer eine Instanz auf das Model UND den View als Attribut besitzen? Wenn man in den Code schaut, dann sieht man ja, dass ich in dem MemoryView einen neuen ChangeIntervallController erstelle, um den Dialog zum Ändern des Intervals anzuzeigen. Um den Dialog auch hinterher modal verwenden zu können, muss ich die Referenz auf das Vater-Fenster ja irgendwie an den Dialog übergeben können.
Habe ich das so ungefähr richtig gemacht? Der MemoryCOntroller kann ja die Referenz auf die View-Komponente zurückgeben. Deshalb habe ich dem ChangeIntervalController über den Konstruktor eine Instanz des Vater-Kontrollers mit übergeben.
Kann man das so machen?
Ich hoffe, dass mir jemand ein wenig kritik und anregung geben kann.
Danke schonmal