Design Patterns en Java
Patterns Observateur et Modèle-Vue-Contrôleur (MVC)
Olivier Goudet
Université d’Angers
10/09/2025
Introduction
I Design pattern Observateur (Observer ) : un des patterns les
plus utilisés.
I MVC : Modèle-Vue-Contrôleur, un assemblage de patterns qui
reprend notamment les patrons de conception Observateur et
Stratégie (cf. cours précédent).
I Utile pour faire des interfaces utilisateur.
I On va en avoir besoin pour le projet.
Section 1
Design pattern Observateur
Exemple d’application - collecte et affichage de données
météorologiques
Objectif
I Créer une application qui utilise l’objet DonneesMeteo pour
actualiser trois affichages différents :
1. un affichage des conditions actuelles
2. un affichage de différentes statistiques météorologiques
3. un affichage de prévisions météo
Premier essai d’implémentation
public class DonneesMeteo {
//Declaration de variables
public void changementMesures() {
float temp = getTemperature();
float humidite = getHumidite();
float pressure = getPressure();
[Link](temp, humidite, pression);
[Link](temp, humidite, pression);
[Link](temp, humidite, pression);
//Autres methodes
}
Quels problèmes peut-on rencontrer avec cette
implémentation ?
Problèmes que l’on rencontre
I La classe DonneesMeteo n’est pas fermée à la modification.
Elle devra être modifiée par la suite si on souhaite ajouter
d’autres types d’affichage.
I Nous n’avons aucun moyen d’ajouter ou de supprimer des
éléments d’affichage au moment de l’exécution.
Design pattern Observateur
I Définition : le pattern Observateur définit une relation entre
objets de type un-à-plusieurs, de façon que, lorsque un objet
change d’état, tous ceux qui en dépendent en soient notifiés
et soient mis à jour automatiquement.
I Avantage : évite de coupler fortement les objets entre eux.
Principe général
Diagramme de classes UML simplifié du design pattern
Observateur
Implémentation de la station météo avec le design pattern
Observateur
I Qui est l’observable ?
I Qui sont les observateurs ?
Création de l’interface Observable
public interface Observable {
public void enregistrerObservateur(Observateur observateur);
public void supprimerObservateur(Observateur observer);
public void notifierObservateurs();
}
Création de l’interface Observateur
public interface Observateur {
public void actualiser(float temp, float humidite, float pression);
}
DonneesMeteo est l’observable dans cet exemple
public class DonneesMeteo implements Observable{
private List<Observateur> observateurs = new ArrayList<>();
private float temperature, humidite, pression;
public void enregistrerObservateur(Observateur observateur){
[Link](observateur);
}
public void supprimerObservateur(Observateur observateur){
[Link](observateur);
}
public void notifierObservateurs() {
for(int i = 0; i< [Link](); i++) {
[Link](i).actualiser([Link], [Link], this
.pression);}
}
Classe DonneesMeteo (suite)
public void setMesures(float temperature, float humidite, float pression)
{
[Link] = temperature;
[Link] = humidite;
[Link] = pression;
notifierObservateurs();
}
//Autres methodes
}
Implémentation d’un premier observateur pour l’affichage
des conditions météo
public class AffichageConditions implements Observateur{
public AffichageConditions(Observable obs) {
[Link](this);
}
public void actualiser(float temp, float humidite, float pression) {
[Link](”Conditions actuelles : ” + temp + ” degres et
” + humidite + ” pourcents d humidite”);
}
}
Implémentation d’un deuxième observateur pour l’affichage
des prévisions
public class AffichagePrevisions implements Observateur{
public AffichagePrevisions(Observable obs) {
[Link](this);
}
public void actualiser(float temp, float humidite, float pression) {
[Link](”Previsions futures : ” + (temp + pression/
humidite) + ” degres.”);
}
}
Classe de test
public class StationMeteo {
public static void main(String[] args) {
DonneesMeteo donneesMeteo = new DonneesMeteo();
AffichageConditions affichageConditions = new
AffichageConditions(donneesMeteo);
AffichagePrevisions affichagePrevisions = new
AffichagePrevisions(donneesMeteo);
[Link](35, 22, 5);
[Link](28, 55, 2);
}
Sorties Console
Console
Conditions actuelles : 35.0 degres et 22.0 pourcents d’humidite
Previsions futures : 35.227272 degres.
Conditions actuelles : 28.0 degres et 55.0 pourcents d’humidite
Previsions futures : 28.036364 degres.
Diagramme de classes UML simplifié du programme
Utiliser directement les APIs Observable et Observer de
Java
I Les classes Observable et Observer peuvent être importées
avec les commandes
import [Link];
import [Link];
I Exemple : documentation Oracle de la classe Observable:
[Link]
util/[Link]
I Exemple : code source de la classe Observable:
[Link]
[Link]
Implémentation de l’observable DonneesMeteo
import [Link];
public class DonneesMeteo extends Observable{
private float temperature, humidite, pression;
public void setMesures(float temperature, float humidite, float pression) {
[Link] = temperature; [Link] = humidite; [Link]
= pression;
setChanged();
notifyObservers();
}
public float getTemperature() {return temperature;}
public float getHumidite() {return humidite;}
public float getPression() {return pression;}
}
Implémentation de l’affichage des conditions météo
import [Link];
import [Link];
public class AffichageConditions implements Observer{
public AffichageConditions(Observable obs) {
[Link](this);
}
public void update(Observable o, Object arg) {
DonneesMeteo donneesMeteo = (DonneesMeteo)o;
[Link](”Conditions actuelles : ” + donneesMeteo.
getTemperature() + ” degres et ” + donneesMeteo.
getHumidite() + ” pourcents d humidite”);
}
}
Implémentation de l’affichage des prévisions météo
import [Link];
import [Link];
public class AffichagePrevisions implements Observer{
public AffichagePrevisions(Observable obs) {
[Link](this);
}
public void update(Observable o, Object arg) {
DonneesMeteo donneesMeteo = (DonneesMeteo)o;
[Link](”Previsions futures : ” + (donneesMeteo.
getTemperature() + [Link]()/
[Link]()) + ” degres.”);
}
}
Le test est le même
public class StationMeteo {
public static void main(String[] args) {
DonneesMeteo donneesMeteo = new DonneesMeteo();
AffichageConditions affichageConditions = new
AffichageConditions(donneesMeteo);
AffichagePrevisions affichagePrevisions = new
AffichagePrevisions(donneesMeteo);
[Link](35, 22, 5);
[Link](28, 55, 2);
}
}
Diagramme de classes UML simplifié avec l’API
[Link]
Pour aller plus loin. Une API plus récente pour
implémenter le design pattern Observateur en Java.
I Utilisation des API PropertyChangeSupport et
PropertyChangeListener.
I De plus en plus utilisées par rapport à l’API Observer qui est
deprecated depuis Java 9.
I Permet de spécifier aux observateurs ce qui a changé dans
l’observable.
I Les observateurs peuvent être notifiés seulement si certains
changements spécifiques se produisent dans l’observable.
I Voir l’exemple de code sur Moodle.
Implémentation de l’observable DonneesMeteo
import [Link];
import [Link];
public class DonneesMeteo{
private final PropertyChangeSupport support = new PropertyChangeSupport(
this);
public void addPropertyChangeListener(PropertyChangeListener listener) {
[Link](listener);
}
public void addPropertyChangeListener(String property,
PropertyChangeListener listener) {
[Link]( property, listener);
}
public void setMesures(float temperature, float humidite, float pression) {
[Link](”temperature”, [Link], temperature);
[Link](”humidite”, [Link], humidite);
[Link](”pression”, [Link], pression);
}
...
}
Implémentation de l’affichage des conditions météo
import [Link];
import [Link];
public class AffichageConditions implements PropertyChangeListener {
public AffichageConditions(DonneesMeteo donneesMeteo) {
[Link](this);
}
public void propertyChange(PropertyChangeEvent evt) {
[Link](”AffichageConditions −− ” + [Link]()
+ ” passe de : ” + [Link]() + ” a ” + [Link]());
}
AffichageConditions s’enregistre en tant qu’observateur pour être
mis au courant de tous les changements dans l’observable
(DonneesMeteo).
Implémentation de l’affichage des températures
import [Link];
import [Link];
public class AffichageTemperatures implements PropertyChangeListener {
public AffichageTemperatures(DonneesMeteo donneesMeteo) {
[Link](”temperature”, this);
}
public void propertyChange(PropertyChangeEvent evt) {
[Link](”AffichageTemperatures −− ” + [Link]()
+ ” passe de : ” + [Link]() + ” a ” + [Link]());
AffichageTemperatures s’enregistre en tant qu’observateur pour
être mis au courant seulement des changements de température.
Test du programme
public class StationMeteo {
public static void main(String[] args) {
DonneesMeteo donneesMeteo = new DonneesMeteo();
AffichageConditions affichageCond = new AffichageConditions(
donneesMeteo);
AffichageTemperatures affichageTemp = new AffichageTemperatures(
donneesMeteo);
[Link](35, 22, 5);
[Link](28, 55, 2);
}
Sorties Console
Console
AffichageConditions – temperature passe de : 0.0 à 35.0
AffichageTemperatures – temperature passe de : 0.0 à 35.0
AffichageConditions – humidite passe de : 0.0 à 22.0
AffichageConditions – pression passe de : 0.0 à 5.0
AffichageConditions – temperature passe de : 35.0 à 28.0
AffichageTemperatures – temperature passe de : 35.0 à 28.0
AffichageConditions – humidite passe de : 22.0 à 55.0
AffichageConditions – pression passe de : 5.0 à 2.0
Section 2
Modèle-Vue-Contrôleur
Modèle-Vue-Contrôleur (MVC)
I MVC : Modèle-Vue-Contrôleur, un assemblage de patterns qui
reprend notamment les patrons de conception Observateur et
Stratégie (cf. cours précédent).
I Implémentation d’un MVC dans le projet Pacman pour gérer
les liens dynamiques entre la vue du jeu, l’interface utilisateur
et l’état du jeu.
Vue d’ensemble du MVC
Utilisation du pattern Observateur
Utilisation du pattern Stratégie
Exemple d’implémentation
I On souhaite définir l’état d’un jeu qui contient différentes
variables comme le nombre de joueurs, le nombre de tours
joués, etc.
I On veut définir une interface utilisateur qui offre des
commandes pour initialiser le jeu et effectuer un tour de jeu.
I L’interface doit permettre aussi de visualiser le nouvel état du
jeu après chaque action de l’utilisateur.
Conception du programme
Implémentation de la classe Game (le modèle dans MVC),
c’est un sujet observable
public class Game extends Observable{
private int turn;
private int maxturn;
private int nbPlayers;
private boolean isOver;
public Game(int nbPlayers, int maxturn) {
[Link] = nbPlayers;
[Link] = maxturn;
}
classe Game (suite)
public void init() {
[Link] = 0;
[Link]();
notifyObservers();
}
public void incrementTurn() {
turn++;
[Link]();
notifyObservers();
}
public void run() {
while(turn < maxturn) {
incrementTurn();
}
[Link] = true;
[Link]();
notifyObservers();
}
}
Implémentation de l’interface utilisateur (la vue dans le
MVC), c’est un observateur.
public class VisualInterface implements Observer{
InterfaceController controller;
JFrame frame;
...
public VisualInterface(InterfaceController controller, Observable
game) {
[Link] = controller;
[Link](this);
[Link]();
}
public void update(Observable obs, Object arg) {
Game game = (Game)obs;
[Link](”Turn : ” + [Link]());
}
public void createUserFrame() {...}
}
Définition d’une stratégie de contrôle pour l’interface
utilisateur (Stratégie abstraite)
public interface InterfaceController {
public void run();
public void reinit();
}
Implémentation d’un premier contrôleur (Stratégie
concrète)
public class Controller1 implements InterfaceController {
private Game game;
public Controller1(Game gameState) {
VisualInterface view = new VisualInterface(this, gameState);
[Link] = gameState;
public void run() {
[Link]();
}
public void reinit() {
[Link]();
}
}
On peut avoir autre type de contrôleur
public class Controller2 implements InterfaceController{
private Game game;
public Controller2(Game game) {
VisualInterface view = new VisualInterface(this, game);
[Link] = game;
}
public void run() {
for(int i = 0; i < 5; i++) {
[Link]();
}
}
public void reinit() {
[Link]();
}
}
Lancement du programme
public class Main {
public static void main(String[] args) {
Game game = new Game(2,10);
Controller1 controller1 = new Controller1(game);
// Ou bien avec un autre controleur
Controller2 controller2 = new Controller2(game);