Ch. 3 — Modèle, Vue(s), Contrôleur(s)
Le patron architectural MVC : découpler l'interface de la logique métier — un modèle unique qui notifie, des vues qui affichent, des contrôleurs qui traduisent les actions de l'utilisateur.
Un patron… architectural
Jusqu'ici, les patrons de conception concernaient quelques classes au plus. Un patron architectural organise à grande échelle : il structure « toutes » les classes du système. Le plus célèbre est le MVC — Modèle / Vue / Contrôleur — dont l'objectif tient en une phrase : découpler l'IHM de la logique applicative.
Ce patron a nourri des travaux en IHM et en génie logiciel, et il a des variations modernes : Modèle-Vue-Présentation (MVP), architecture en 3 couches, etc.
La triade MVC
| Rôle | C'est quoi | Points clés |
|---|---|---|
| Modèle | le cœur fonctionnel : données, aspects métier, règles | unique (mais composé de plusieurs classes), indépendant de la vue, contient le plus de traitement possible |
| Vue(s) | la représentation graphique des données du modèle | plusieurs possibles, pas de traitement métier, ne modifie pas le modèle directement |
| Contrôleur(s) | associé(s) à une vue : récupère les événements utilisateur | peut vérifier la validité des données, transmet au modèle — pas de vérifications métier |
Le Modèle en détail
- Le modèle est unique — mais il peut être composé de plusieurs classes : c'est une organisation abstraite du code, pas un seul fichier.
- Il est complètement indépendant de la vue : le même modèle doit pouvoir fonctionner sous
JavaFX ou Android — donc pas d'
import javafx.*dans le modèle. - Il doit contenir le plus de traitement possible.
- Quand il change (valeur d'un attribut), il avise chaque vue — et chaque vue se met à jour, ou pas : c'est elle qui décide.
- Il ne dit jamais à la vue quoi afficher ni comment l'afficher.
Les Vues en détail
- Il peut y avoir plusieurs vues — au choix, ou simultanément.
- Une vue n'est pas nécessairement une classe : c'est une notion logique — une fenêtre, ou une partie cohérente d'une fenêtre. Elle peut être composée de plusieurs objets.
- Elle ne contient que du code relié à l'affichage.
- Elle ne modifie pas le modèle directement (mais elle peut lui passer des instructions de l'utilisateur : incrémenter/décrémenter une valeur, transmettre une saisie).
- Elle ne fait pas de calcul qui pourrait être dans le domaine.
Les Contrôleurs en détail
- Associés aux vues — donc plusieurs contrôleurs possibles, chacun avec plusieurs classes.
- Ils récupèrent les événements et les nouvelles données de la vue.
- Ils peuvent faire des vérifications simples : « est-ce que cette date existe ? ».
- Ils ne font pas de vérifications liées au métier : « est-ce que la date de facturation correspond à l'année fiscale ? » — ça, c'est le domaine du modèle.
- Ils transmettent au modèle, qui se met à jour en conséquence.
Le défi : notifier des vues inconnues
Comment le modèle fait-il pour notifier ses vues, alors que leur nombre est inconnu (aucune, une, plusieurs) et leur type aussi (JavaFX, Android, web…) ? C'est exactement le problème résolu par le patron Observable / Observateurs du cours 2 : le modèle est observable, les vues s'abonnent à lui et se mettent à jour à chaque notification. Le MVC s'appuie donc sur le patron Observer — les deux chapitres se répondent.
Deux interprétations du cycle — nous utiliserons la première
Dans l'interprétation retenue par le cours : la vue passe l'action au contrôleur, qui modifie le modèle ; le modèle notifie les vues ; les vues récupèrent les données auprès du modèle (mode pull, cours 2). D'autres projets font interagir la vue et le contrôleur de façon plus symétrique (« voit », « interagit ») — les deux variantes circulent, il faut savoir les reconnaître.
Exemple du cours : une calculatrice très simple
L'application : un champ de saisie (3 + 2), un bouton « Calcul ! », un champ résultat (5).
L'approche « intuitive » (sans MVC)
bouton.setOnAction((ev) -> {
String entree = txtEntree.getText();
int resultat = calculResultat(entree);
txtResultat.setText("" + resultat);
});Tout tient dans le gestionnaire d'événement… et c'est là le problème : plus difficile à tester (le calcul est prisonnier de la fenêtre), et si on ajoute une deuxième vue, on duplique la logique.
L'approche MVC
- Vue : fenêtre, bouton, champs texte ;
- Contrôleur : l'
ActionListenerdu bouton ; - Modèle : l'interprétation de la formule saisie et le calcul du résultat.
Le contrôleur, ici intégré dans la vue, ne fait que transmettre :
// Dans la vue : l'action du bouton délègue au modèle
bouton.setOnAction((ev) -> {
String entree = txtEntree.getText();
this.modele.majResultat(entree);
});Le modèle fait le travail et notifie ses observateurs :
public class CalculetteModele {
protected int resultat;
protected Set<CalculetteObservateur> obs;
public void majResultat(String entree) {
this.resultat = this.calculResultat(entree);
this.notifyObservers();
}
// + méthodes add / remove / notifyObservers (cours 2)
}La vue, observatrice du modèle, récupère les données à la notification (mode pull) :
class CalculetteVue implements CalculetteObservateur {
public CalculetteVue(CalculetteModele modele) {
modele.add(this); // abonnement
// ...
}
public void update(CalculetteModele modele) {
int resultat = modele.getResultat(); // la vue va chercher la donnée
txtResultat.setText("" + resultat);
}
}Variante mode push : le modèle envoie directement la donnée dans la notification
(notifyObservers(resultat)), et la vue la reçoit (update(int resultat)).
Contrôleur séparé : la version complète
On peut aussi sortir le contrôleur dans sa propre classe — c'est la version la plus propre :
public class CalculetteControleur {
protected CalculetteModele modele;
protected CalculetteVue vue;
public void appuiSurEntree() {
this.modele.majResultat(vue.getEntree());
}
}La vue crée le contrôleur et lui délègue l'action du bouton
(this.controleur.appuiSurEntree()). Chacun son rôle : la vue montre, le contrôleur traduit,
le modèle calcule.
A retenir
Patron architectural :
- organisation logique de classes à grande échelle ;
- favorise l'indépendance des parties (surtout le modèle) ;
- plusieurs variations existent (MVP, 3 couches…).
Patron MVC :
- modèle unique, indépendant du reste, qui contient le métier ;
- plusieurs vues, pas de traitements métier, qui observent le modèle ;
- plusieurs contrôleurs, qui gèrent les actions utilisateur et informent le modèle.
ch3-mvc.pdf
R3.04 · Cours 3 — Fabien Delecroix, base de Nicolas Anquetil · 28 diapositives
Chargement du document…
Dernière mise à jour le
Ch. 2 — Observable et observateurs
Programmation événementielle, abonnement, notification, réaction : le patron Observer — comment un objet prévient d'autres objets d'un changement sans rien connaître d'eux.
Ch. 4 — Tests
Pourquoi tester, les grands types de tests, JUnit 5 — et les règles pour écrire du code qui se laisse tester : responsabilités nettes, exceptions vérifiées, calculs séparés de l'interface.