CentraleSupélecDépartement informatique
Plateau de Moulon
3 rue Joliot-Curie
F-91192 Gif-sur-Yvette cedex
Génie logiciel orienté objet - Exercice : Conception du modèle métier du projet intégré

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 ;
  • camelCase est 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 slidingblock et activer la propriété Java element dans l'onglet Java.
  • Créer un paquetage gloo à l'intérieur du paquetage slidingblock, un paquetage projet à l'intérieur du paquetage gloo, un paquetage metier à l'intérieur du paquetage projet, et un diagramme de classes dans ce paquetage metier.
  • 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 case comme 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 paquetage projet.
  • Créer une classe Controleur à l'intérieur du paquetage controle.

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 paquetage metier, 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).

  • Quels objets le contrôleur doit-il connaître ? glisser-déposer la classe Controleur sur 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

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é Bloc de l'association entre Plateau et Bloc.
  • Dans l'onglet Java, choisir HashMap as Map comme Collection to use, et Integer comme Key.
  • 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, choisir Generate HashCode() and equals(), sélectionner uniquement les attributs ligne et colonne et cliquer sur Generate, 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é AbstractCase de l'association entre Plateau et AbstractCase.
  • Dans l'onglet Java, choisir HashMap as Map comme Collection to use, et Position comme Key.
  • 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 Plateau et Position.

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é AbstractCase de l'association entre AbstractCase et Position.
  • 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 (x est un numéro de ligne, y un numéro de colonne) : une position sur le plateau.
  • cxy, mxy ou sxy (x est un numéro de ligne, y un numéro de colonne) : les différentes cases du plateau (c pour une case normale, m pour un mur, s pour les cases de sortie).
  • b et be : 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 Controleur pour 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 sont 1, 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 Plateau pour 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 classe Plateau.
  • 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'une Position sera 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