Une conception sur le moèle MVC (Model-View-Controller)

L'application est représentée par les deux images ci-dessous. Quand on appuie sur le bouton trace, le disque rouge apparaît, quand on appuie sur le bouton efface, le disque disparaît. :

     

On utilise toujours ici la classe Ardoise.

Les applications peuvent être complexes, ainsi que l'interface correspondante. Il peut alors être souhaitable de séparer

Le schéma ci-contre illustre ce modèle (il y a différentes variantes) :

Dans le schéma ci-dessus, Observer est la classe java.util.Observer. Cette classe possède la méthode addObserver qui permet d'inscrire des observateurs, de type java.util.Observable. L'interface java.util.Observable déclare uniquement la méthode :
    public void update(Observable o, Object arg);.
Le modèle étend la classe Observer et l'interface graphique est inscrite comme observateur du modèle. Quand le modèle est modifié, il faut en général actualiser l'interface graphique ; le modèle n'a pas besoin pour cela de connaître l'interface graphique ; après une modification, elle utilise les instructions :
    setChanged();
    notifyObservers();

ce qui a pour conséquence de faire exécuter les méthodes update des observateurs inscrits pour observer le modèle.
On remarque que le modèle ne connaît ni la vue, ni le contrôleur, que la vue connaît le modèle, que le controleur connaît la vue et le modèle.
En un certain sens, par le mécanisme Observer-Observable la vue est un listener du modèle, même si le nom de listener n'est pas utilisé dans ce contexte.

Dans un programme plus complexe, il peut y a voir un paquetage pour le modèle contenant plusieurs classes, un paquetage pour un ensemble de contrôleurs, un paquetage pour différentes classes décrivant la vue.

Le modèle est dans notre exemple particulièrement simple puisqu'il contient qu'un attribut booléen nommé existe. On peut considérer que l'absence ou la présence du disque dans l'insterface graphique illustre le fait que le booléen existe vaut false ou true dans le modèle

Le programme ci-dessous est composé selon cette architecture.

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observer;
import java.util.Observable;

class Vue extends JFrame implements Observer {
Modele modele;
JButton trace = new JButton("trace");
JButton efface = new JButton("efface");
Ardoise ardoise = new Ardoise();

Vue(Modele modele) {
this.modele = modele;
JPanel lesBoutons = new JPanel();

modele.addObserver(this); lesBoutons.add(trace); lesBoutons.add(efface); add(lesBoutons, BorderLayout.NORTH); add(ardoise, BorderLayout.CENTER); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocation(200,200); pack(); setVisible(true);
}

public void update(Observable o, Object arg) {
ardoise.setPossedeDisque(modele.getExiste());
ardoise.repaint();
}
}

class Modele extends Observable {
private boolean existe;

void setExiste(boolean existe) {
this.existe = existe;
setChanged(); notifyObservers(); } boolean getExiste() {
return existe;
}
}

class Controleur implements ActionListener {
Modele modele;
Vue vue;

Controleur(Modele modele, Vue vue) {
this.modele = modele;
this.vue = vue;
}

public void actionPerformed(ActionEvent e) {
if (e.getSource() == vue.trace) modele.setExiste(true);
else if (e.getSource() == vue.efface ) modele.setExiste(false);
}
}

class EssaiBoutons5 {
public static void main(String[] arg) {
Modele modele = new Modele();
Vue vue = new Vue(modele);
Controleur controleur = new Controleur(modele, vue);

vue.trace.addActionListener(controleur); vue.efface.addActionListener(controleur); } }
Pour accéder au fichier Boutons5.java.


public void update(Observable o, Object arg) : cette méthode est prototypée dans l'interface Observable ; elle sera exécutée quand le modèle indique qu'il a changé et notifie ses observateurs.
setChanged(); notifyObservers(); : les observateurs du modèle vont être prévenus du changement, ce qui signifie que leur méthode update va être exécutée.
modele.addObserver(this); : la vue s'inscrit ainsi comme observateur du modèle.
vue.trace.addActionListener(controleur); : cette instruction figure ici car la vue ne connaît pas le contrôleur.

© Irène Charon Télécom ParisTech 2012