Introduction aux
patrons de conception
d’applications
Frédéric Claux – 2019
CC BY-NC-ND – [email protected]
Contenu d’une application
• Des données
• Du code, qui utilise les données
La donnée
• Existe de plein droit
• Indépendamment des applications
• Exemple
• Base de données météo
• Application 1
• Prévisions
• Application 2
• Visualisation des données sur une carte
• Application 3
• Qui sait ce que l’avenir nous réserve ?
Données et traitements
• Données
• Un graphe
• Application
• Compter le nombre de nœuds
de ce graphe
• Implémentation typique
• Méthode recursive
• Chaque nœud visité augmente compteur
• On délègue vers les nœuds liés
Données et traitements
• Implémentation typique
• Méthode recursive
• Chaque nœud visité augmente compteur
• On délègue vers les nœuds liés
class Noeud
{
Char lettre;
Noeud[] noeuds_adjacents;
}
Données et traitements
class Noeud
{
Char lettre;
Noeud[] noeuds_adjacents;
}
int compte_noeuds(Noeud n)
{
return 1 + <compte_noeuds(chaque nœud adjacent)>
}
Données et traitements
int compte_noeuds(Noeud n)
{
return 1 + <compte_noeuds(chaque nœud adjacent)>
}
Problème:
Eviter de visiter une deuxième fois
un nœud déjà visité !
Ce qu’il ne faut PAS faire
class Noeud
{
Char lettre;
Noeud[] noeuds_adjacents;
boolean visité;
}
On ne met pas dans les données
des informations qui relèvent des
traitements
Advertisement
Données et traitements
Set<Nœud> nœuds_deja_visités;
int compte_noeuds(Noeud n)
{
if (nœuds_deja_visités.contains(n))
return 0;
else {
nœuds_deja_visités.add(n);
return 1 + <compte_noeuds(chaque nœud adjacent)>
}
}
Données et traitements
Données
Traitement
(comptage)
Données associées
Set<Nœud> nœuds_déjà_visités;
Données et traitements
• Nous avons parlé d’une situation sans interface utilisateur
• i.e. pour illustrer un programme en ligne de commande par exemple
• Incorporons maintenant la problématique de l’interface utilisateur
• Appelons un traitement une opération ou contrôleur
Ajoutons une interface utilisateur
• Considérons une application
avec
plusieurs contrôleurs.
• Une interface utilisateur est
proposée
pour chaque étape
Liste des clients et des commandes
• L’application lance un contrôleur qui consiste à renvoyer la liste de
tous les clients et toutes leurs commandes associées
• On associe une interface ou vue à contrôleur permettant de voir les
données récupérées, et d’agir dessus
• Agir dessus = pouvoir avoir plus de détails, ou bien d’éditer des
données
Détails d’une commande
• Pour avoir les détails d’une commande, l’utilisateur clique sur « voir
détails commande », sur la commande en cours de sélection dans la
vue
Détails d’une commande
• Le contrôleur détails d’une commande va chercher les différents
articles d’une commande et propose une vue sur les données
récupérées
• Un clic sur les entêtes de colonnes permet de tirer le détail de la
commande par article, par quantité ou discount octroyé
• Il est possible de revenir
à la liste des clients/commandes
Edition d’un client
• La vue associée au contrôleur listant clients et commandes permet
d’éditer le client en cours de sélection
• Elle lance un traitement (contrôleur) d’édition de client, qui ira
chercher les détails d’un client et proposera une vue d’édition de ces
détails
Flux des opérations
• ListeDesClientsEtCommande()
{ Clients et commandes associées }
• EditionDUnClient(<id client>)
{ Client }
• ModificationDuClient(<id client>, <nouveau nom>, <nouveau prénom>, etc.)
{ Message de succès ou d’échec de la modification }
•
ListeDesClientsEtCommande()
{ Clients et commandes associées }
• DétailsDUneCommande(<id commande>)
{ Liste d’articles }
• DétailsDUneCommande(<id commande>, <trier suivant telle colonne>)
Advertisement
{ Liste d’articles }
• ListeDesClientsEtCommande()
{ Clients et commandes associées }
Flux des opérations
• ListeDesClientsEtCommande()
{ Clients et commandes associées }
• EditionDUnClient(<id client>)
{ Client }
• ModificationDuClient(<id client>, <nouveau nom>, <nouveau prénom>, etc.)
{ Message de succès ou d’échec de la modification }
•
ListeDesClientsEtCommande()
{ Clients et commandes associées }
• DétailsDUneCommande(<id commande>)
{ Liste d’articles }
• DétailsDUneCommande(<id commande>, <trier suivant telle colonne>)
{ Liste d’articles }
• ListeDesClientsEtCommande()
{ Clients et commandes associées }
Flux des opérations
• ListeDesClientsEtCommande()
{ Clients et commandes associées }
• EditionDUnClient(<id client>)
{ Client }
• ModificationDuClient(<id client>, <nouveau nom>, <nouveau prénom>, etc.)
{ Message de succès ou d’échec de la modification }
•
ListeDesClientsEtCommande()
{ Clients et commandes associées }
• DétailsDUneCommande(<id commande>)
{ Liste d’articles }
• DétailsDUneCommande(<id commande>, <trier suivant telle colonne>)
{ Liste d’articles }
• ListeDesClientsEtCommande()
{ Clients et commandes associées }
Flux des opérations
• Un contrôleur est exécuté (une opération, quelconque)
• Le contrôleur propose une vue
• La vue permet
• de voir les données packagées par le contrôleur
• de lancer d’autres opérations (donc contrôleurs)
Propriétés générales de ce modèle
• Le traitement est parfaitement défini
• Ce qu’il fait
• Avec quelles données (en paramètres)
• La vue n’a aucune logique. Elle peut juste
• Lire les données fournies par le contrôleur
• Appeler un autre contrôleur, avec les seules données qui lui sont parvenues
• Libre au contrôleur d’exposer tout ou partie du modèle central à la
vue
Cahiers des charges ?
• Ce modèle répond-il au cahier des charges général de développement
d’applications ?
• Ce modèle répond-il aux exigences des développeurs relatives au
confort de développement ?
Développement d’application
Cahier des charges
• Bien définir et représenter les données
• Pas de mélange données de modèle / données de traitement
• Ne pas mettre « d’état » dans le modèle
• Effectuer un ensemble de traitements définis sur ces données
• Chaque traitement est clairement défini, détaché
• Pas d’interdépendance entre les traitements (pas d’état à maintenir)
• Proposer une interface utilisateur efficace pour réaliser ces traitements
• Un contrôleur met à disposition des données pour consultation, ou pour agir sur ces
données
• Pouvoir modifier facilement l’interface utilisateur
Advertisement
Exemple du web: changement de style « présumé facile et rapide »
• La vue n’a aucun code. Elle est facilement éditable.
Confort côté conception - Modèle
• Isoler la définition du modèle
• Isolé dans une classe Modèle
• Assurer une continuité de typage entre les modèles et le code
• Cours précédent
Confort côté conception - traitements
• Chaque traitement
• Prend en paramètre des données bien définies
• Créé une structure de données à-même de déboucher sur d’autres
traitements
• Ping-pong contrôleur/vue. Ping-pong interface/traitement.
• Tester/valider les traitements (tests unitaires)
• Pas besoin de créer une interface pour tester des traitements
• Pour les tests unitaires on évite simplement de créer des vues
Confort côté conception - interface
• Pouvoir changer d’interface
• Y compris de technologie sous-jacente
• Il faut juste pouvoir appeler un contrôleur avec des paramètres et pouvoir
manipuler les données de retour
• Permettre à des non-développeurs de travailler sur l’interface
Métiers focalisés sur l’expérience utilisateur (UX)
• L’interface n’a pas de code
• Elle se branche sur le modèle de données du traitement
• Les outils existent pour éditer l’interface suivant ce modèle
• Microsoft Blend (Visual Studio)
• Java FXML Form Designer
• etc.
Modèle MVVM
• Model
• View
• Contrôleur
• ViewModel
• Les données associées au traitement
• Les actions initiables par la vue
• ViewModel: importance donnée
Modèle de données
e
d
è
c
c
a
Traitement
produit
Données
n
u
e
h
c
n
e
l
c
é
d
Vue
à cette classe, qui cloisonne la vue dans des données bien définies
Modèle MVVM
• John Gossman (Microsoft), 2005
• Windows Presentation Foundation
• Silverlight (WPF dans le navigateur)
• ASP.NET MVC ~= MVVM
• De nombreux autres frameworks dérivés
• Populaire sur le web notamment
Advertisement
Détails non abordés
• En principe, un contrôleur a plusieurs fonctions qui donnent lieu à des
view models différents
• Pour nous, 1 contrôleur = 1 fonction (méthode), avec 1 seule vue associée
(Par conséquent 1 contrôleur = 1 view model)
• Redirection d’un contrôleur vers un autre
• Evite de passer par une interface dédiée entre 2 contrôleurs
e.g. interface quasi vide « Enregistrement créé avec succès ! »
Extra slides
• Comparaison avec d’autres modèles
Modèle document/vue
• Séparation des données d’un côté, interface et traitements de
l’autre, pêle-mêle
• Populaire car intuitif pour réaliser rapidement une application,
très simplement
• Exemple: bouton cliqué dans une vue
• Lecture dans une base de données
• Paramétrage des traitements faite avec des données puisées dans
l’interface utilisateur
• Traitements sur ces données
• Mise à jour de la base et des données de l’interface
• Rafraichissement de la (ou les) vue(s)
• Comment faire des tests unitaires ?
• Les traitements et la vue sont entremêlés : il faut créer une vue.
• Si la vue est une page web, fabriquer une page web pour tester ?
• Lourd
Données
Interface utilisateur
+ traitements
Modèle Vue Contrôleur (circa 1978)
• Les traitements
• demandent à la vue ses données
• réalisent des opérations avec
• ces données
• les données du modèle central
• Mettent à jour les données du modèle central
Données
Traitements
(Contrôleur)
Vue/Interface
(avec données
propres à l’interface)
Modèle Vue Contrôleur (circa 1978)
• La vue tire les données à afficher du modèle
seulement
• Etat de l’interface dans le modèle, sauf à mettre
(hélas) du code dans la vue
Données
Traitements
(Contrôleur)
Vue/Interface
(avec données
propres à l’interface)
Code de démarrage pour le projet
• 4 projets à importer dans Eclipse et examiner
• Contrôleurs (4 contrôleurs simples proposés)
• Vues (4 vues simples associées)
• Modèle (1 modèle de film simple)
• Application/infrastructure
• Permet de coordonner le tout
• Mappage 1:1 entre le nom des contrôleurs et des vues associées, mais dans deux
projets différents
• Bibliothèques graphiques restreintes aux vues
• Ne pas ajouter de code dans les vues SWT autre que lors de la création de l’UI
• la gestion des clics ne doit faire qu’appeler runController()