Un pattern puissant : le pattern MVC
Voici un chapitre qui risque d'être dur à digérer...
En effet, si le DP
MVC est un outil puissant, il n'en est pas moins l'un des patterns les plus compliqués à assimiler et à utiliser.
Ce dernier n'est pas qu'un pattern : il s'agit d'un pattern composé, ce qui signifie qu'il est constitué d'au moins deux patterns (mais ça peut être plus).
Nous allons voir ceci tout de suite, inutile de tergiverser plus longtemps !
Dans ce chapitre, nous n'allons pas faire comme d'habitude :
- créer une situation ;
- voir ce que nous pouvons faire ;
- découvrir le pattern.
Je pense que, vu qu'il s'agit d'un pattern compliqué, nous allons directement rentrer dans le vif du sujet... Voici un schéma que ceux qui ont déjà fait des recherches sur ce pattern ont dû déjà voir et revoir :
Avant d'expliquer ce schéma, nous devons faire un point sur ce que sont réellement ces trois entités !
La vue
Ce qu'on nomme la vue est en fait une IHM. Celle-ci est en fait ce qu'a l'utilisateur sous les yeux. La vue peut donc être :
- une application graphique swing, awt, swt pour Java (Form pour C#...) ;
- une page web, vous connaissez...
- un terminal Linux ou une console Windows...
- ...
Le modèle
Le modèle peut être divers et varié. il s'agit en général d'un ou plusieurs objets Java (ou bean, nous y reviendrons). Ces objets s'apparentent généralement à ce qu'on appelle souvent "
la couche métier" de l'application.
Ce sont des objets qui font des traitements absolument transparents pour l'utilisateur. Par exemple, on peut citer des objets dont le rôle est de gérer une ou plusieurs tables d'une base de données.
En trois mots, il s'agit du
cœur du programme !
Dans le chapitre précédent, nous avons confectionné une petite horloge. Dans cette application, notre fenêtre
swing correspond à la vue et l'objet
Horloge correspond au modèle.
Le contrôleur
Cet objet - car il s'agit aussi d'un objet - permet de faire le lien entre la vue et le modèle lorsqu'une interaction utilisateur est survenue sur la vue ! C'est cet objet qui aura pour rôle de contrôler les données et, le cas échéant, ira dire au modèle qu'il peut utiliser les données envoyées par l'utilisateur en toute tranquillité !
Maintenant que toute la lumière est faite sur les trois composants de ce pattern, nous allons expliquer un peu plus la façon de travailler de ce dernier.
Pour commencer, vous pouvez constater que les trois composants sont tous en interaction les uns avec les autres.
Si nous partons du postulat que votre application, implémentant le pattern MVC, est chargée, voici ce qu'il peut se passer :
- l'utilisateur fait une action sur votre calculatrice (clic sur un bouton) ;
- l'action est captée par le contrôleur qui va vérifier la cohérence des données et, le cas échéant, transformer celles-ci afin d'être comprises par le modèle. Le contrôleur peut aussi demander à la vue de changer...
- le modèle reçoit les données et change d'état (une variable qui change, par exemple...) ;
- le modèle notifie à la vue (ou aux vues) qu'elle (qu'elles) doit (doivent) se mettre à jour ;
- l'affichage dans la vue est modifié en conséquence en allant chercher l'état du modèle.
On y voit déjà plus clair, mais tu nous as dit que MVC est un pattern composé... Il est donc construit avec plusieurs patterns ?
Tout à fait : en fait, avec les chapitres que vous avez vus, vous pouvez isoler deux patterns dans cette architecture.
Je crois voir du pattern observer...
Bien ! Je vois que vous avez bien suivi le chapitre précédent...
Il y a en effet le pattern observer au niveau du modèle.
Comme ceci, lorsque celui-ci va changer d'état, tous les objets qui l'observeront seront mis au courant automatiquement et cela, avec un couplage faible !
Le deuxième est plus difficile à voir mais il s'agit du pattern strategy !

Ce pattern est situé au niveau du contrôleur.
On dit aussi que le contrôleur est la strategy de la vue !
En fait, le contrôleur va transférer les données de l'utilisateur au modèle et il a tout à fait le droit de modifier le contenu. Donc, s'il y a des contrôles à faire, la vue aura une implémentation du pattern strategy afin de
centraliser les contrôles et découpler encore plus le modèle de la vue !
On ne comprend pas trop pourquoi utiliser le pattern strategy alors que le pattern observer aurait suffit !
Souvenez-vous de la raison d'être du pattern strategy :
encapsuler les morceaux de code qui changent !
Avec l'utilisation de ce pattern, vous prévenez les risques potentiels de changements dans votre logique de contrôle ! Il vous suffira d'utiliser une autre implémentation de votre contrôleur afin d'avoir des contrôles différents.

Ceci dit, vous devez tout de même savoir que le modèle et le contrôleur sont intimement liés :
un objet contrôleur pour notre calculatrice ne servira que pour notre calculatrice ! Nous pouvons donc autoriser un couplage fort entre ces deux objets !
Vous comprenez le pourquoi du comment maintenant...
Je pense qu'il est temps de se mettre à coder !
Le modèle sera l'objet qui sera chargé de stocker les données nécessaires à un calcul (nombre et opérateur) et d'avoir le résultat !

Afin de prévoir un changement éventuel de modèle, nous allons créer celui-ci à partir d'un super-type de modèle : comme ça, si un changement s'opère, nous pourrons utiliser les différentes classes filles de façon polymorphe.
Avant de foncer tête baissée, nous allons devoir réfléchir à ce que notre modèle doit savoir faire...
Afin de faire des calculs simples, celui-ci devra pouvoir :
- récupérer et stocker au moins un nombre ;
- stocker l'opérateur de calcul ;
- renvoyer le résultat ;
- calculer le résultat ;
- tout remettre à zéro.
Très bien : voici donc la liste des méthodes que nous trouverons dans notre classe abstraite.
Comme vous le savez, nous allons utiliser le pattern observer afin de faire communiquer notre modèle avec d'autres objets... Il nous faudra donc une implémentation de ce pattern ; le voici, dans un package
com.sdz.observer
.
Observable.java
Code : Java1
2
3
4
5
6
7 | package com.sdz.observer;
public interface Observable {
public void addObserver(Observer obs);
public void removeObserver();
public void notifyObserver(String str);
}
|
Observer.java
Code : Java1
2
3
4
5 | package com.sdz.observer;
public interface Observer {
public void update(String str);
}
|
Notre classe abstraite devra donc implémenter ce pattern afin de centraliser les implémentations.
Vu que notre super-type implémente le pattern observer, les classes héritant de cette dernière hériteront aussi des méthodes de ce pattern !
Voici donc le code de notre classe abstraite que nous placerons dans le package
com.sdz.model
.
AbstractModel.java
Code : Java 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 | package com.sdz.model;
import java.util.ArrayList;
import com.sdz.observer.Observable;
import com.sdz.observer.Observer;
public abstract class AbstractModel implements Observable{
protected double result = 0;
protected String operateur = "", operande = "";
private ArrayList<Observer> listObserver = new ArrayList<Observer>();
/**
* Efface
*/
public abstract void reset();
/**
* Effectue le calcul
*/
public abstract void calcul();
/**
* Affichage forcé du résultat
*/
public abstract void getResultat();
/**
* Définit l'opérateur de l'opération
* @param operateur
*/
public abstract void setOperateur(String operateur);
/**
* Définit le nombre à utiliser pour l'opération
* @param nbre
*/
public abstract void setNombre(String nbre) ;
//**************************************************
// IMPLÉMENTATION PATTERN OBSERVER
//**************************************************
public void addObserver(Observer obs) {
this.listObserver.add(obs);
}
public void notifyObserver(String str) {
if(str.matches("^0[0-9]+"))
str = str.substring(1, str.length());
for(Observer obs : listObserver)
obs.update(str);
}
public void removeObserver() {
listObserver = new ArrayList<Observer>();
}
}
|
Ce code est clair et simple à comprendre ; maintenant, nous allons créer une classe concrète héritant de
AbstractModel.
Voici la classe concrète que j'ai créée.
Calculator.java
Code : Java 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 | package com.sdz.model;
import com.sdz.observer.Observable;
public class Calculator extends AbstractModel{
//**************************************************
// MÉTHODES DE CLASSES
//**************************************************
/**
* Définit l'opérateur
*/
public void setOperateur(String ope){
//On lance le calcul
calcul();
//On stocke l'opérateur
this.operateur = ope;
//Si l'opérateur n'est pas =
if(!ope.equals("=")){
//On réinitialise l'opérande
this.operande = "";
}
}
/**
* Définit le nombre
* @param result
*/
public void setNombre(String result){
//On concatène le nombre
this.operande += result;
//On met à jour
notifyObserver(this.operande);
}
/**
* Force le calcul
*/
public void getResultat() {
calcul();
}
/**
* Réinitialise tout
*/
public void reset(){
this.result = 0;
this.operande = "0";
this.operateur = "";
//Mis à jour !
notifyObserver(String.valueOf(this.result));
}
/**
* Calcul
*/
public void calcul(){
//S'il n'y a pas d'opérateur, le résultat est le nombre saisi
if(this.operateur.equals("")){
this.result = Double.parseDouble(this.operande);
}
else{
//Si l'opérande n'est pas vide, on calcule avec l'opérateur de calcul
if(!this.operande.equals("")){
if(this.operateur.equals("+")){
this.result += Double.parseDouble(this.operande);
}
if(this.operateur.equals("-")){
this.result -= Double.parseDouble(this.operande);
}
if(this.operateur.equals("*")){
this.result *= Double.parseDouble(this.operande);
}
if(this.operateur.equals("/")){
try{
this.result /= Double.parseDouble(this.operande);
}catch(ArithmeticException e){
this.result = 0;
}
}
}
}
this.operande = "";
//On lance aussi la mise à jour !
notifyObserver(String.valueOf(this.result));
}
}
|
Vous ne devriez avoir aucun souci à comprendre ce code, sinon, retournez faire un tour dans
la partie 3 du tutoriel !
Voilà, notre modèle est prêt à l'emploi !
Nous allons donc continuer à créer les composants de ce pattern...
Celui-ci sera chargé de faire le lien entre notre vue et notre modèle.
Pour la même raison que pour le modèle :
polymorphisme ! Nous créerons aussi une classe abstraite afin de définir un super-type de variable pour, au cas où, utiliser des contrôleurs de façon polymorphe...
Que doit faire notre contrôleur, ici ?
C'est lui qui va intercepter les actions utilisateur, qui va modeler les données et les envoyer au modèle !
Il devra donc :
- agir lors d'un clic sur un chiffre ;
- agir aussi lors du clic sur un opérateur ;
- avertir le modèle pour qu'il se réinitialise dans le cas d'un clic sur le bouton 'reset' ;
- contrôler les données !
Voilà donc notre liste de méthodes pour cet objet. Cependant, vu que notre contrôleur doit interagir avec le modèle, celui-ci devra avoir une instance de notre modèle !
Voici donc le code source de notre super-classe de contrôle.
AbstractControler.java
Code : Java 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 | package com.sdz.controler;
import java.util.ArrayList;
import com.sdz.model.AbstractModel;
public abstract class AbstractControler {
protected AbstractModel calc;
protected String operateur = "", nbre = "";
protected ArrayList<String> listOperateur = new ArrayList<String>();
public AbstractControler(AbstractModel cal){
this.calc = cal;
//On définit la liste des opérateurs afin d'être sûr qu'ils soient bons
this.listOperateur.add("+");
this.listOperateur.add("-");
this.listOperateur.add("*");
this.listOperateur.add("/");
this.listOperateur.add("=");
}
/**
* Définit l'opérateur
* @param ope
*/
public void setOperateur(String ope){
this.operateur = ope;
control();
}
/**
* Définit le nombre
* @param nombre
*/
public void setNombre(String nombre){
this.nbre = nombre;
control();
}
/**
* Efface
*/
public void reset(){
this.calc.reset();
}
/**
* Méthode de contrôle
*/
abstract void control();
}
|
Nous avons défini les actions globales à notre objet de contrôle et vous constatez aussi qu'à chaque action dans notre contrôleur, celui-ci invoque la méthode
control()
.
Celle-ci va vérifier les données et informer le modèle en conséquence.
Nous allons voir maintenant ce que doit faire notre instance concrète.
Voici donc, sans plus tarder, notre classe.
CalculetteControler.java
Code : Java 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 | package com.sdz.controler;
import com.sdz.model.AbstractModel;
public class CalculetteControler extends AbstractControler {
public CalculetteControler(AbstractModel cal) {
super(cal);
}
void control() {
//On notifie le modèle d'une action si le contrôle est bon
//--------------------------------------------------------
//Si l'opérateur est dans la liste
if(this.listOperateur.contains(this.operateur)){
//Si l'opérateur est =
//On informe le modèle d'afficher le résultat
if(this.operateur.equals("="))
this.calc.getResultat();
//Sinon, on passe l'opérateur au modèle
else
this.calc.setOperateur(this.operateur);
}
//Si le nombre est conforme
if(this.nbre.matches("^[0-9.]+$")){
this.calc.setNombre(this.nbre);
}
this.operateur = "";
this.nbre = "";
}
}
|
Vous pouvez voir que celle-ci redéfinit la méthode
control()
et qu'elle permet de dire quelles informations envoyer à notre modèle ! Celui-ci mis à jour, les données à afficher dans la vue seront envoyées via l'implémentation du pattern observer entre notre modèle et notre vue.
D'ailleurs, il ne nous manque plus qu'elle.

Donc, allons-y !
Voici le plus facile à développer et celui que vous devez maîtriser le mieux...
Nous allons créer celui-ci avec le package
javax.swing
. Vous devriez maintenant avoir l'habitude de créer des IHM, mais si vous ne voulez pas répéter ce que vous avez déjà fait, vous pouvez récupérer mon code d'IHM de calculatrice dans le
TP correspondant.
Il va de soi que, vu que les traitements sont tous dans cette classe, nous allons enlever un grand nombre de classes internes !
Je vous donne donc le code source de notre classe que j'ai mis dans le package
com.sdz.vue
.
Calculette.java
Code : Java 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149 | package com.sdz.vue;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import com.sdz.controler.*;
import com.sdz.observer.Observer;
public class Calculette extends JFrame implements Observer{
private JPanel container = new JPanel();
String[] tab_string = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", ".", "=", "C", "+", "-", "*", "/"};
JButton[] tab_button = new JButton[tab_string.length];
private JLabel ecran = new JLabel();
private Dimension dim = new Dimension(50, 40);
private Dimension dim2 = new Dimension(50, 31);
private double chiffre1;
private boolean clicOperateur = false, update = false;
private String operateur = "";
//Notre instance de notre objet contrôleur
private AbstractControler controler;
public Calculette(AbstractControler controler){
this.setSize(240, 260);
this.setTitle("Calculette");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setResizable(false);
initComposant();
this.controler = controler;
this.setContentPane(container);
this.setVisible(true);
}
private void initComposant(){
Font police = new Font("Arial", Font.BOLD, 20);
ecran = new JLabel("0");
ecran.setFont(police);
ecran.setHorizontalAlignment(JLabel.RIGHT);
ecran.setPreferredSize(new Dimension(220, 20));
JPanel operateur = new JPanel();
operateur.setPreferredSize(new Dimension(55, 225));
JPanel chiffre = new JPanel();
chiffre.setPreferredSize(new Dimension(165, 225));
JPanel panEcran = new JPanel();
panEcran.setPreferredSize(new Dimension(220, 30));
//Nous utiliserons le même listener pour tous les opérateurs
OperateurListener opeListener = new OperateurListener();
for(int i = 0; i < tab_string.length; i++)
{
tab_button[i] = new JButton(tab_string[i]);
tab_button[i].setPreferredSize(dim);
switch(i){
case 11 :
tab_button[i].addActionListener(opeListener);
chiffre.add(tab_button[i]);
break;
case 12 :
tab_button[i].setForeground(Color.red);
tab_button[i].addActionListener(new ResetListener());
tab_button[i].setPreferredSize(dim2);
operateur.add(tab_button[i]);
break;
case 13 :
case 14 :
case 15 :
case 16 :
tab_button[i].setForeground(Color.red);
tab_button[i].addActionListener(opeListener);
tab_button[i].setPreferredSize(dim2);
operateur.add(tab_button[i]);
break;
default :
chiffre.add(tab_button[i]);
tab_button[i].addActionListener(new ChiffreListener());
break;
}
}
panEcran.add(ecran);
panEcran.setBorder(BorderFactory.createLineBorder(Color.black));
container.add(panEcran, BorderLayout.NORTH);
container.add(chiffre, BorderLayout.CENTER);
container.add(operateur, BorderLayout.EAST);
}
//**********************************************
// LES LISTENERS POUR NOS BOUTONS
//**********************************************
class ChiffreListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
//On affiche le chiffre en plus dans le label
String str = ((JButton)e.getSource()).getText();
if(!ecran.getText().equals("0"))
str = ecran.getText() + str;
controler.setNombre(((JButton)e.getSource()).getText());
}
}
class OperateurListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
controler.setOperateur(((JButton)e.getSource()).getText());
}
}
class ResetListener implements ActionListener{
public void actionPerformed(ActionEvent arg0) {
controler.reset();
}
}
//************************************************
// IMPLEMENTATION DU PATTERN OBSERVER
//************************************************
public void update(String str) {
ecran.setText(str);
}
}
|
Vous devez être à même de comprendre ce code vu qu'il ressemble beaucoup à notre calculette faite dans le TP de la partie 3...

Il y a une nouveauté toutefois, une instance de notre contrôleur ! Celui-ci, je le rappelle, sera la strategy de notre vue...
Notre classe devra donc inclure une instance de notre implémentation du pattern strategy : vous pouvez voir celle-ci juste avant le constructeur de notre classe.
Voilà, toutes nos classes sont opérationnelles.
Il ne nous manque plus qu'une classe de test afin de voir le résultat...
La voici :
Code : Java 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | import com.sdz.controler.*;
import com.sdz.model.*;
import com.sdz.vue.Calculette;
public class Main {
public static void main(String[] args) {
//Instanciation de notre modèle
AbstractModel calc = new Calculator();
//création du contrôleur
AbstractControler controler = new CalculetteControler(calc);
//Création de notre fenêtre avec le contrôleur en paramètre
Calculette calculette = new Calculette(controler);
//Ajout de la fenêtre comme observer de notre modèle
calc.addObserver(calculette);
}
}
|
Testez ce code et le tout fonctionne très bien !
Tous nos objets sont inter-connectés et dialoguent facilement.
Vu que vous connaissez la façon de travailler de ce pattern, nous allons décortiquer ce qu'il se passe.
Lorsque vous cliquez sur un chiffre
- L'action est envoyée au contrôleur.
- Celui-ci vérifie si le chiffre est conforme.
- Il informe le modèle.
- Celui-ci est mis à jour et informe la vue de ses changements.
- Celle-ci rafraîchit son affichage.
Lorsque vous cliquez sur un opérateur
- L'action est toujours envoyée au contrôleur.
- Celui-ci vérifie si l'opérateur envoyé est dans sa liste.
- Le cas échéant, il informe le modèle.
- Celui-ci agit en conséquence et informe la vue de son changement.
- La vue est mise à jour...
La même chose se passe lorsque nous cliquerons sur le bouton "
reset".
Voilà une bonne chose de faite !
Nous aurions très bien pu faire la même chose sans le contrôleur !
Oui, bien sûr. Même sans modèle !
Rappelez-vous du pourquoi de l'existence des DP :
prévenir des modifications de codes !
Avec une telle architecture, vous pourrez modifier indépendamment l'un des trois composants de ce pattern.
Si vous ne voulez plus de nombres à virgules à l'affichage mais uniquement des entiers, vous pouvez créer un autre modèle qui ne travaille que sur des entiers !
De même, si vous voulez bloquer certains chiffres ou certains opérateurs, il vous suffit de coder une autre classe héritant de
AbstractControler qui, elle, ne laissera pas passer tel ou tel choix utilisateur !
Je ne vous donne pas d'exemple pour la vue, nous avons déjà abordé cela dans le chapitre sur le pattern observer.

Oh et puis si, tenez ! C'est encore un des exemples les plus simples qu'on puisse faire...
Au lieu de gérer l'affichage dans notre classe
Calculette, nous allons créer une classe
Ecran, toujours dans notre package
com.sdz.vue
, dans laquelle nous allons afficher tout ce que nous renvoie le modèle !
Voici cette classe.
Ecran.java
Code : Java 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 | package com.sdz.vue;
import java.awt.*;
import javax.swing.*;
import com.sdz.observer.Observer;
public class Ecran extends JFrame implements Observer{
private JLabel ecran = new JLabel();
public Ecran(Component c){
this.setSize(300, 100);
this.setLocationRelativeTo(c);
this.setResizable(false);
Font police = new Font("DS-digital", Font.BOLD, 50);
this.ecran.setFont(police);
this.ecran.setHorizontalAlignment(JLabel.RIGHT);
this.getContentPane().add(this.ecran, BorderLayout.CENTER);
this.setVisible(true);
}
public void update(String str) {
ecran.setText(str);
}
}
|
Et voici notre nouveau code de test :
Code : Java 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | import com.sdz.controler.AbstractControler;
import com.sdz.controler.CalculetteControler;
import com.sdz.model.AbstractModel;
import com.sdz.model.Calculator;
import com.sdz.vue.Calculette;
import com.sdz.vue.Ecran;
public class Main {
public static void main(String[] args) {
AbstractModel calc = new Calculator();
AbstractControler controler = new CalculetteControler(calc);
Calculette calculette = new Calculette(controler);
//On crée notre Ecran
Ecran ecran = new Ecran(calculette);
//On informe que c'est l'instance d'écran qui écoutera notre modèle
calc.addObserver(ecran);
}
}
|
Et le résultat :
Vous pouvez aussi séparer les chiffres des opérateurs... Enfin, faire ce que vous voulez, quoi...
Avant de terminer ce chapitre, vous devez savoir encore quelques choses...
Ce pattern est aussi utilisé lorsque vous développez avec la plateforme J
EE et, pour être tout à fait honnête, il en est même le principe de base !
Si vous vous rappelez le schéma dont je me suis servi dans le chapitre sur les applets, vous devriez vous souvenir du cycle de vie d'une page web ! Pour mémoire :
Nous reviendrons plus en détail sur le développement web en Java, mais, pour le moment, sachez seulement que vos fichiers seront interprétés et utilisés par
le serveur d'applications.
Le principe de fonctionnement pour le couple JSP - Servlet est le suivant :
Le schéma est assez explicite.
Vous pouvez voir que les servlets ont le rôle de contrôleurs, les JSP sont les vues et les objets métiers correspondent à votre modèle !
Cependant, un problème pouvait se poser.
En effet, dans certaines boîtes de développement, les tâches sont réparties entre plusieurs développeurs :
- certains seront chargés de développer les objets métiers ;
- d'autres s'occuperont des servlets ;
- et enfin, une troisième équipe sera en charge des vues.
Seulement voilà, les développeurs en charge des vues ne sont peut-être pas des développeurs Java ! Or, avec l'implémentation du pattern MVC vue ci-dessus, il n'était pas rare de trouver des portions de codes Java dans vos pages JSP...
Un peu comme ceci :
Code : Java 1
2
3
4
5
6
7
8
9
10
11
12
13
14 | <html>
<body>
<%
String[] langage = {"Java", "C++", "C#", "PHP"};
out.println("<p>Langage de programmtion :");
out.println("<ul>");
for(String str : langage)
out.println("<li>" + str + "</li>");
out.println("</ul>");
out.println("</p>");
%>
</body>
</html>
|
Le but de ce chapitre n'étant pas le développement web en Java, je n'expliciterai pas plus ce code ainsi que les suivants. Une partie sera consacrée à cet effet !
Ceci pouvait être dérangeant dans la mesure où un développeur web n'a peut-être pas les connaissances requises pour inclure des portions de code Java dans les pages !
C'est à ce niveau que le pattern
M2VC entre en jeu !
Le principe de celui-ci est de pouvoir appliquer le pattern MVC et de séparer les tâches de développement. Ainsi, un développeur web n'a plus qu'à insérer des tags (balises JSP) spécifiés par les développeurs des autres couches applicatives.
En gros, la servlet va communiquer un objet (bean) à la page JSP afin que celle-ci puisse utiliser les informations de ce dernier. Ainsi, le développeur web n'a plus qu'à utiliser une balise propre aux JSP pour afficher le contenu souhaité. Voici un exemple illustrant mes propos :
Code : Java1
2
3
4
5
6
7
8 | <%jsp:useBean id="compteur" class="Counter" scope="session" />
<html>
<body>
<p>
Affichage de l'attribut "total" de l'objet : <jsp:getProperty name="compteur" property="total" /> <br />
</p>
</body>
</html>
|
Ainsi, les développeurs web n'ont plus à connaître le langage Java, juste à savoir récupérer les informations que leur transmettent les autres couches applicatives !
Le modèle, dans cette architecture, n'avertit plus seulement les vues d'un changement d'état, mais elle leur fournit un ou plusieurs objets pouvant répondre à leurs demandes.
Avant de vous envoyer sur le topo habituel, vous devez savoir encore une petite chose.
Dans le schéma que je vous ai fourni au début de chapitre, le contrôleur passe des informations au modèle. Mais vous pourrez peut-être voir que, parfois,
le contrôleur fait partie des observateurs du modèle...
Maintenant, nous pouvons voir le topo !
- Le pattern MVC est un pattern composé.
- Celui-ci est composé du pattern observer et du pattern strategy.
- L'implémentation du pattern observer permet au modèle de tenir informés ses observateurs.
- L'implémentation du pattern strategy permet à la vue d'avoir des contrôles différents.
- Utiliser ce pattern permet de découpler trois acteurs d'une application, ce qui permet plus de souplesse et de maintenabilité dans la durée de vie de celle-ci.
- Pour la conception d'applications web, on utilise le pattern M2VC.
Toutefois, je mets aussi un bémol à ce pattern. Bien qu'il soit très utile grâce à ses avantages à long terme.
Cependant, vous avez pu constater que
celui-ci complique grandement votre architecture !
Un chapitre très riche en informations.
Il faut toutefois que vous sachiez qu'il y a encore un pattern, caché, dans l'implémentation de MVC. En soit, il n'est pas vraiment dans les classes que vous avez programmées, mais plutôt dans le langage Java !
En effet, vous ne le savez sûrement pas, mais vos composants swing, comme AWT, utilisent un pattern afin de coexister.
Du coup, lorsque vous utilisez une de ces deux bibliothèques, vous utilisez de façon tacite ce pattern.
Je vous propose donc de voir comment fonctionne le pattern composite.
Informations sur le tutoriel
Retour en haut
Créé : Le 21/06/2006 à 15:02:22
Modifié : Le 17/06/2009 à 11:19:46
Avancement : 100%
Licence : Copie non autorisée
2 commentaires