Un petit projet conçu avec UML et programmé en Java doit être réalisé dans le cadre de cet électif. Ce travail peut-être effectué en binôme (voir les modalités sur la page Edunao du cours).
Le sujet retenu est la réalisation d'une application permettant de jouer à un jeu de type Sliding Block, un puzzle où il faut réussir à sortir d'un plateau un bloc identifié en déplaçant d'autres blocs pour libérer le passage.
Par rapport à la description figurant sur le site, la terminologie et les modifications suivantes sont retenues :
- le plateau est constitué de cases, chaque case est repérée par un numéro de ligne et un numéro de colonne ;
- il n'y a pas de blocs gris, mais des cases spéciales, que l'on appellera murs, qui n'autorisent pas la présence d'un bloc ;
- il n'y a pas un bloc jaune et des blocs bleus, mais l'un des blocs sera identifié comme principal ;
- les blocs sont numérotés (pour faciliter l'affichage), le bloc principal a le numéro 0 ;
- pour déplacer un bloc, il faudra le sélectionner puis le déplacer avec les flèches du clavier.
L'objectif de cet exercice est de commencer la conception du modèle métier de cette application en utilisant UML et Java. La fin de la conception et de la réalisation en Java seront faites en autonomie.
Cet exercice est principalement une activité de conception. Donc, et contrairement à l'exercice sur l'école primaire :
- les attributs et rôles seront protégés ou privés ; les accesseurs et modifieurs nécessaires seront générés par l'outil ou ajoutés directement dans le code Java ;
- les opérations doivent être identifiées (on utilise pour cela les diagrammes de séquence) ;
- les associations seront initialement navigables dans les deux sens ; on supprimera ensuite les navigabilités non nécessaires ;
- les classes d'associations peuvent être utilisées au départ, mais il faudra les convertir en associations simples avant le fin de la conception.
Première conception des classes
- En vous basant sur la description du jeu, proposer une liste de classes possibles accompagnées d'une courte phrase de description (responsabilité de la classe).
Deux objets sont des instances d'une même classe s'ils ont la même structure de représentation et le même comportement. Donc deux objets ayant des comportements différents sont des instances de classes différentes.
L'objectif est une réalisation en Java, nous utiliserons donc dès le départ les conventions de nommage de Java :
- les noms de classes commencent par une majuscule ;
- les noms des paquetages, des attributs, des rôles et des opérations commencent par une minuscule ;
camelCaseest utilisé (sauf pour les paquetages).
Solution retenue
Plateau: représente la surface de jeu, c'est un rectangle avec un nombre de lignes et un nombre de colonnes ; il y a une case carrée à chaque couple (numéro de ligne, numéro de colonne).Case: un carré sur le plateau, repéré par un numéro de ligne et numéro de colonne. Une case peut avoir une partie d'un bloc sur elle.Mur: une case n'acceptant pas de bloc.Sortie: une case n'acceptant qu'un bloc principal.Bloc: un élément pouvant être déplacé et occupant une ou plusieurs case contigües.BlocElementaire: un constituant d'un bloc, il est sur une case.
- Créer avec Modelio un nouveau projet SlidingBlock.
- Déployer le module Java Designer dans le projet, sélectionner le paquetage
slidingblocket activer la propriété Java element dans l'onglet Java. - Créer un paquetage
glooà l'intérieur du paquetageslidingblock, un paquetageprojetà l'intérieur du paquetagegloo, un paquetagemetierà l'intérieur du paquetageprojet, et un diagramme de classes dans ce paquetagemetier.

- Proposez un modèle avec classes, attributs et associations, en précisant les multiplicités des extrémités de celles-ci.
- L'auto-completion est disponible dans certains contextes (par exemple pour renseigner un type), il s'obtient avec
CTRL-Espace.
- On adoptera la bonne pratique que seules les feuilles de l'arbre d'héritage sont des classes concrètes.
- Vous réfléchirez spécifiquement à une bonne représentation de la position des cases pour éviter une duplication d'information.
- Ne pas utiliser
casecomme nom de rôle : c'est un mot réservé en Java.
Solution retenue

Ajout du contrôleur
Dans le cadre de la mise en œuvre du patron d'architecture MVC (Model-View-Controller) (qui sera vu plus tard), nous avons besoin d'une classe Controleur ; celle-ci servira d'intermédiaire entre les objets de l'interface homme-machine (IHM) et les objets métiers ; l'unique instance de cette classe recevra via l'IHM les demandes de l'utilisateur, et fournira à l'IHM les informations nécessaires à l'affichage de l'état du jeu.
- Créer un paquetage
controleà l'intérieur du paquetageprojet.
- Créer une classe
Controleurà l'intérieur du paquetagecontrole.
Vous pouvez directement créer des éléments de modélisation avec le menu contextuel dans la vue du modèle.
Les actions de jeu seront des clics sur une case (repérée par un numéro de ligne et un numéro de colonne) et des demandes de déplacement du bloc sélectionné dans une direction ; nous représenterons les 4 directions possibles par une énumération.
- Créer une énumération
Directionà l'intérieur du paquetagemetier, ajouter 4 litéraux correspondant aux 4 directions.
Cette énumération sera aussi utilisée pour définir des opérations dans le modèle métier. Pour ne pas faire dépendre le paquetage metier du paquetage controle, l'énumération est définie côté métier.
Par convention, les valeurs d'énumération en Java sont en majuscules.
L'IHM appellera des méthodes du contrôleur pour l'informer des actions du joueur.
- Dans la classe
Controleur:- créer une opération
selection(ligne : integer, colonne : integer), - créer une opération
action(direction : Direction).
- créer une opération

- Quels objets le contrôleur doit-il connaître ? glisser-déposer la classe
Controleursur votre diagramme de classes, ajouter les associations correspondantes.
Solution retenue
Le Controleur doit connaître le plateau pour obtenir le bloc cliqué, et le bloc sélectionné pour lui transmettre les demandes de déplacement (soit un lien, soit un attribut mémorisant son numéro).
Les objets métiers ne doivent pas être impactés par l'existence de ce contrôleur, nous utiliserons donc ici des associations navigables dans un seul sens.
Création du projet Eclipse
- Demander à Modelio de générer le code Java du projet.
- Lancer Eclipse et créer le projet Java associé (il sera nommé
gloo.projet). - Configurer Modelio pour une relecture correcte du code Java.
Choix de la représentation des associations
La question de cette représentation se pose quand la cardinalité maximale à l'extrémité d'une association est *.
Cas simple : Bloc vers BlocElementaire
Un bloc a besoin d'accéder à ses éléments pour le déplacement (donc un changement de case pour chaque bloc élémentaire) et pour l'affichage (obtenir les coordonnées des cases recouvertes). Un bloc n'a pas besoin d'identifier un bloc élémentaire particulier, donc un dictionnaire n'est pas nécessaire. Nous retenons donc une solution simple utilisant les ArrayList, c'est justement celle retenue par défaut par Modelio (voir le fichier Bloc.java).
Cas avec une clef simple : Plateau vers Bloc
Pour l'affichage, l'IHM commencera par représenter les différentes cases, puis représentera par dessus les différents blocs en demandant au contrôleur les coordonnées des cases recouvertes pour chaque bloc identifié par son numéro. Le contrôleur doit donc pouvoir accéder à un bloc à partir de son numéro : un dictionnaire, en utilisant le numéro comme clef, est la solution la plus simple.
- Sélectionner l'extrémité côté
Blocde l'association entrePlateauetBloc. - Dans l'onglet Java, choisir
HashMap as MapcommeCollection to use, etIntegercommeKey. - Générer le code Java et vérifier dans Eclipse la prise en compte de ce choix.
- Dans Modelio, faire un reverse et vérifier que la clef est bien prise en compte.
Cas avec une clef complexe : Plateau vers AbstractCase
Le plateau est responsable de l'accès aux cases, il doit donc doit donc proposer un service d'accès à une case à partir d'une position. Pour que la classe Position puisse être utilisée comme clef d'un dictionnaire, ses méthodes equals() et hashCode() doivent être correctement définies.
- Dans Eclipse, ouvrir le fichier
Position.java, positionner le curseur dans la classe. - Dans le menu
Source, choisirGenerate HashCode() and equals(), sélectionner uniquement les attributsligneetcolonneet cliquer surGenerate, sauvegarder les changements effectués. - Dans Modelio, faire un reverse et vérifier la présence des deux opérations.
- Sélectionner l'extrémité côté
AbstractCasede l'association entrePlateauetAbstractCase. - Dans l'onglet Java, choisir
HashMap as MapcommeCollection to use, etPositioncommeKey. - Générer le code Java et vérifier dans Eclipse la prise en compte de ce choix.
- Dans Modelio, faire un reverse et vérifier que la clef est bien prise en compte.
Le plateau utilisera les positions comme clefs, il n'a donc pas besoin d'une association vers Position. De même, Position ne dépend pas du plateau.
- Supprimer l'association entre
PlateauetPosition.
Une position ne donnera pas directement accès à une case (c'est le plateau qui a la responsabilité de fournir l'accès aux cases). Par contre, une case devra avoir accès à sa position.
- Supprimer la navigabilité sur l'extrémité côté
AbstractCasede l'association entreAbstractCaseetPosition. - Générer le code Java et vérifier dans Eclipse la prise en compte de ce choix.
- Dans Modelio, faire un reverse et vérifier que tout est correct.
Solution retenue

Conception du comportement
Le comportement est modélisé par le séquencèrent des échanges de messages entre objets. Pour identifier les opérations impliquées dans ces échanges, nous allons dérouler ces séquences de jeu et les représenter dans des diagrammes de séquence.
Nous prendrons le plateau suivant comme base des différents scénarios :

Un diagramme de séquence permet de représenter temporellement des envois de messages entre objets, nous avons donc besoin de nommer ceux-ci :
c: le contrôleur.p: le plateau.pxy(xest un numéro de ligne,yun numéro de colonne) : une position sur le plateau.cxy,mxyousxy(xest un numéro de ligne,yun numéro de colonne) : les différentes cases du plateau (cpour une case normale,mpour un mur,spour les cases de sortie).betbe: le bloc bleu et son bloc élémentaire.j,jb,jh: le bloc jaune (principal) constitué de ses deux blocs élémentaires en bas et en haut.
Première action
On suppose que la première action du joueur est de cliquer sur le bloc bleu.
- Créer un diagramme de séquence dans le paquetage
slidingblock.
- C'est l'IHM qui recevra les actions de jeu du joueur : créer une ligne de vie sur le diagramme de séquence pour représenter l'IHM.
- L'IHM transmet au contrôleur les demandes du joueur : glisser-déposer sur le diagramme de séquence la classe
Controleurpour créer une ligne de vie associée à l'unique instance de cette classe. - Ajouter sur le diagramme un envoi de message synchrone de l'IHM vers le contrôleur ; préciser que l'opération associée est
selection(ligne : integer, colonne : integer)et que les arguments sont1, 1.

Concevons la suite du déroulement : que fait le contrôleur quand il reçoit ce message ? Son objectif est de mémoriser le bloc sélectionné pour lui transmettre ensuite les demandes de déplacement, mais il n'a pas directement accès aux blocs, il doit donc demander au plateau.
- Glisser-déposer sur le diagramme de séquence la classe
Plateaupour créer sa ligne de vie. - Ajouter le message synchrone du contrôleur vers le plateau.
- Créer une opération
getBloc(ligne : integer, colonne : integer)dans la classePlateau. - Associer le message synchrone à cette opération, préciser les arguments.
Le plateau n'a pas directement accès aux blocs via une numéro de ligne et un numéro de colonne. Par contre, il peut obtenir la case située à cette position.
- La recherche d'une
caseà partir d'unePositionsera utile dans d'autres scénarios, on décide d'en faire une opération spécifique. - Poursuivre la conception en complétant le diagramme.
Vous devez essayer de jouer le rôle d'un objet qui reçoit un message : avez-vous dans vos attributs les informations permettant de répondre au service demandé : si oui, alors vous pouvez directement répondre ; si non, alors vous connaissez certainement un autre objet qui pourra répondre, au moins en partie : demandez-lui !
Solution possible

Déplacement vers la gauche
Une fois le bloc bleu sélectionné, nous supposeront que le joueur appuyé sur la flèche gauche.
- Réaliser le diagramme de séquence correspondant.
La « politesse » est une qualité qui est utile lors de la conception pour améliorer la modularité. Ainsi, ce n'est pas le bloc qui va regarder s'il peut utiliser les cases correspondant à son déplacement. Au contraire, chaque bloc élémentaire va demander à la case où il doit se rendre si celle-ci est d'accord : un mur dira non, une case de sortie n'acceptera que si c'est le bloc principal, une case déjà occupée n'acceptera que si le bloc élémentaire qui l'occupe appartient au bloc déplacé.
Déplacement vers la droite
Cette fois, le joueur appuyé sur la flèche droite.
- Réaliser le diagramme de séquence correspondant.
Vous pouvez, dans Modelio, copier-coller des éléments de modélisation dans l'onglet Model, y compris des interactions.
Actions suivantes
Quand ces scénarios sont terminés, envisager le déplacement du bloc principal (il n'est pas nécessaire de refaire le scénario de sélection).

© 2025 CentraleSupélec