Jeux Libres

Plateforme de création de jeux vidéo (Le site est en cours de création / réorganisation)


» Les Tutoriaux » La programmation de jeux avec le langage Java » Les associations entre classes et objets

Les associations entre classes et objets


Ici nous allons voir qu'il y a plusieurs façon d'associer les objets entre eux.
Et nous allons voir comment faire communiquer ces objets entre eux dans chacun des cas. =)





Chapitre précédent     Sommaire     Chapitre suivant


La composition


Partie II (suite)



En fait, je vous l'ai déjà fait faire sans que vous le sachiez, et oui!
Lorsque je vous ai fait créer les objets dans le constructeur de votre classe maison!

Aller je vous remet le code!
Code : Java

public Maison () {
        toit = new Triangle (150, 10, 50, 150, "black");
        toit.makeVisible ();
        mur = new Square (90, 60, 120, "red");
        mur.makeVisible ();
        fenetreGauche = new Square (100, 70, 40, "blue");
        fenetreGauche.makeVisible ();
        fenetreDroite = new Square (160, 70, 40, "blue");
        fenetreDroite.makeVisible ();
        porte = new Square (130, 140, 40, "black");
        porte.makeVisible ();
}
 


Les objets toit, mur, etc... sont créer dans le constructeur de la classe Maison.
De ce fait, il sont stocker dans l'espace mémoire de l'objet maison.

Schéma de ce que cela donne ne mémoire centrale :


Il s'agit là d'une bête composition d'objets, d'ou les objets composants sont les objets toit, murs, etc... et l'objet composite est la maison.

Inconvénient de ce type de relation.

Vu que les objets composants sont créer dans l'espace mémoire de l'objet composite, les objets composants sont supprimés de la mémoire en même temps que l'objet composite!

Pour accéder à une variable, ou méthode d'un objet composants, il faut passer par l'objet composite.
Exemple : Si vous voulez bouger le toit de la maison vous devez écrire :
Code : Java

Maison maison.getToit().move ();
 


N'oublier pas de déclarer vos variables toit, mur, etc... au début de votre classe maison!


L'agrégation


Là, on ne va plus créer les objets des autres classes dans le constructeur, mais on va les passer en arguments au constructeur même, et ensuite, copier les références des variables des autres classes. (donc les paramètres des constructeurs, aussi appelés ici attributs référents)
Et copie donc ces attribut référent dans les variables que vous avez déclarer au début de votre classe.
Exemple :
Code : Java

public class Maison {
       private Triangle toit;
       private Square mur, fenetreGauche, fenetreDroite, porte;
public Maison (Triangle toit, Square mur, Square, fenetreGauche, Square fenetreDroite, Square porte) {
        this.toit = toit;
        this.mur = mur;
        this.fenetreGauche = fenetreGauche;
        this.fenetreDroite = fenetreDroite;
        this.porte = porte;
    }
....
}
 

Là on voit clairement la différence vis à vis de la composition : on fait une copie par référencement des objets toit, mur, etc...
En mémoire, donc, les objets toit, murs etc.... ne sont plus créer dans l'espace mémoire de l'objet maison, mais en dehors.
Alors lorsque l'objet maison sera supprimée de la mémoire, les objets toit, murs, etc... existerons encore, car ce seront les copies des référents qui pointent vers les objets qui seront supprimés et pas les objets eux même!
Ceci implique que les objets toit, mur, etc... doivent être créer avant que l'on crée la maison pour pouvoir les passer en arguments au constructeur de ma classe maison.

Voici donc comment ça se représente en mémoire. (oui je sais, mes schéma sont mal fait!)


La dépendance


Je n'ai pas vraiment d'exemple pour voue l'illustrer, mais sachez que c'est rarement utiliser.
En général, on utilise souvent une agrégation ou une composition d'objets pour relier les classes entre elles avec ces objets de type différents.

Le problème de la dépendance, c'est que là, on ne passe plus les objets en argument dans le constructeur de la classe, mais dans une de ses méthodes.
Donc, l'association ne dure que le temps de l'exécution de la méthode.
En fait on fait comme ceci :
Code : Java

public void travaillerPourObjet2 (Objet1 o1) {
       Objet1 objet1 = o1;
}
 


Là on voit que l'on déclare l'objet dans la méthode et non plus au début de la classe comme dans le cas de la composition et de l'agrégation.
Et ensuite on copie le référent passé en argument à la méthode dans le corps de celle-ci, de se fait, l'objet passé en argument existe toujours mais la copie qui sert de lien n'existe que le temps de l'exécution de la méthode travaillerPourObjetO2.
Donc l'objet qui sert de lien est stocker dans la mémoire des méthodes de la classe de l'objet 2!

En représentation mémoire, ça donne ceci :


C'est une autre manière moins utilisée pour permettre d'associer les classes entre elles.

Voilà, on a vu les différentes possibilités de lier les classes entre elles. (Par composition, agrégation ou dépendance)
On va maintenant voit les faire interagir entre eux.
on verra aussi l'ordre d'exécution des méthodes par le diagramme de séquence, que je vous montrerez lorsque je pourrez héberger des images sur ce site.


Communications entre les objets de classes différentes


Il y a plusieurs façon de le faire.
Donc on a vu comment créer des relations entre les différentes classes, on va voir maintenant comment on peut donc procéder pour utiliser les méthodes d'autres classes sur ces relations.

L'appel d'une méthode sur un objet appartenant à une autre classe (l'objet destinataire) à partir d'une méthode invoqué sur un objet s'appelle un envoi de message :
Exemple :
Code : Java

public void moveToit () {
        toit.moveDown ();
    }
 


Lorsqu'on fera appel ici à la méthode moveToit () sur un objet de type maison, on voit bien que l'on appelle dans cette méthode la méthode moveDown sur l'objet toit. (qui est l'objet destinataire!)

La donc on voit clairement que des objets appartenant à des classes différentes peuvent interragir entre eux!

Il y a deux manières de procédé, la première c'est ce que je viens de vous montrer, c'est à dire, par envoi de message.

Que ce soit par la composition ou par l'agrégation, ou la dépendance, l'envoi de message est toujours réalisé de la même façon, ce qui change, c'est la manière de créer le lien entre les différentes classes!
Si on a une classe Objet1 comme ceci :
Code : Java

public class Objet1 {
       //variables de Objet1
       public Objet1 () {
            //Constructeur de Objet1
       }
       public void travaillerPourObjet1 () {
             System.out.println("Je travaille pour l'objet 1!");
       }
}
 

Cas de la composition :
Code : Java

public class Objet2 {
       private Objet1 o1;
       public Objet2 () {
              o1 = new Objet1 ();
       }
       public void travaillerPourObjet2 ();
              o1.travaillerPourObjet1 ();
              System.out.println ("Je travaille pour l'objet 2!");       
       }
}
 

Ce qui nous donne comme schéma en mémoire :



Cas de l'agrégation :
Code : Java

public class Objet2 {
       private Objet1 o1;
       public Objet2 (Objet1 o1) {
              this.o1 = o1;
       }
       public void travaillerPourObjet2 ();
              o1.travaillerPourObjet1 ();
              System.out.println ("Je travaille pour l'objet 2!");       
       }
}
 


En schéma cela nous donne :

Cas de la dépendance :
Code : Java

public class Objet2 {
       variable de Objet2     
       public Objet2 () {
              //Constructeur de Objet2
       }
       public void travaillerPourObjet2 (Objet1 objet);
              Objet1 o1 = objet;
              o1.travaillerPourObjet1 ();
              System.out.println ("Je travaille pour l'objet 2!");       
       }
}
 

Ce qui nous donne : (cette fois-ci je vous ai mit le lien pour bien voir que c'est l'objet lien qui appelle la méthode!)



La gestion d'évènement
Imaginer que l'on a une classe Voiture et une classe FeuDeSignalisation.

Soit on fait comme on a fait ci dessus, quand le feu passe au vert, il appel la méthode démarrer de la classe Voiture!
Ca s'appelle donc comme on l'a vu, l'envoi de message.

Mais il y a aussi une autre manière de procéder : La voiture attend que le feu soit vert avant de démarrer.
Donc là, le message se fait dan l'autre sens, et ça s'appelle la gestion d'évènement.

En effet, il faut vérifier le moment ou le feu passe au vert avant que la voiture démarre, c'est plus dans le cadre de la programmation événementionnelle que l'on verra dans la partie III.

Voici donc les 2 procédés qui se résument en deux schéma :
L'envoi de message :


La gestion d'évènements :


Voilà, ici s'arrête donc ce chapitre important, sur les associations entre les classes.
on voit là donc bien l'importance, et la facilité de conception qu'apporte la POO!


Les diagrammes de séquences


L'ordre d'exécution des méthodes



Les méthodes appelées sur les objets ne peuvent être exécutées en même temps.
Le Java les exécutent en formant une pile de méthode, et toutes méthodes incluse dans uen autre, se retrouve au dessus de la pile, et la méthode qui se trouve en dessous doit attendre que celle du dessus ai fini de s'exécuter pour reprendre son exécution là ou elle s'était arrêtée.

Si nous reprenons nos classes Objet1 et Objet2 du tutoriel précédent, on remarque que dans la méthode travaillerPourObjet2() on fait appel à la méthode travaillerPourObjet1()
Lors de l'exécution, la pile d'exécution des méthodes se crée comme ceci :


Lorsque notre méthode travaillerPourObjet1 est appelée, elle est envoyée au dessus de la pile et l'autre méthode est mise en attente.

Et tant que la méthode travaillerPourObjet1 n'a pas fini de s'exécuter, la méthode travaillerPourObjet2 reste bloquée!

Utilité des diagramme de séquences.



Là, le temps d'exécution se représente verticalement avec en haut le nom des classes et des objets qui appelle la méthode.

Ce diagramme sera utile lorsque nous nous intéresseront à créer des tâches parallèles pour l'exécution de nos méthodes. (Plusieurs piles d'exécution) Ce qui nous permettra de prendre contrôle des différentes tâches de notre programme. (on verra cela dans la partie avec la gestion du temps)

L'appel d'une méthode que recherche une autre méthodes se fait par une flèche.

Voici donc comment se représente le diagramme de séquence :

Object 1 représente l'exécution de notre méthode main, et on voit qu'il y a une flèche qui part vers objet2, c'est l'appel de la méthode traillerPourObjet2.
Le temps d'exécution de la méthode main s'interrompt (rectangle vide) et la méthode travaillerPourObjet2 s'exécute.
Ensuite on a cette méthode qui fait appel à la méthode travaillerPourObjet1
Et la méthode travaillerPourObjet2 s'interrompt.
Ensuite quand la méthode travaillerPourOblet1 a finie son exécution, on reviens à la méthode travaillerPourObjet2 et ensuite, au main et le programme à fini son exécution lorsque la méthode main a terminer sa pile d'exécution des méthodes!

Voilà donc comment marche et comment on représente l'exécution des méthodes en Java.


Exercices


1) Maintenant pour voir si vous avez bien compris, je vous propose donc de créer une classe feu de signalisation, qui sera composée de trois spots, donc il vous faudra créer une classe Spot composée d'un cercle (l'ampoule) et d'un rectangle (le support), ensuite une classe FeuDeSignalisation, qui sera composée de trois spot, un pourle feu rouge, un pour le feu orange, et un pour le feu vert.

Il faut bien entendu pouvoir faire bouger le feu et lui faire changer de couleur.

Pour la durée du feu orange, comme on a pas encore vu la gestion du temps, je vous mets le code :
Code : Java

 try {
     Thread.sleep (2000);
} catch (Exception e) { }
 

L'instruction Thread.sleep "endore" le programme pendant 2000 millisecondes.

Vous pouvez changer la valeur si ça ne vous convient pas.

Ensuite pour terminer, créer la classe Carrefour comportant 2 rues et 2 feu de Signalisations : un feu pour la rue qui part vert le haut, et un autre pour la rue qui part vers la droite.

Et faîtes une méthode qui permet de faire alterner le feu, si l'un est rouge, l'autre devient vert et vis versa.


Solution des exercices.


Vous n'aurez peut-être pas la même chose que moi, mais en gros c'est ça. (ce code si marche chez moi en tout cas)
La classe Spot :
Code : Java
public class Spot
{
private int x, y;
private int size;
private Circle ampoule;
private Square contour;
public Spot () {
contour = new Square (150, 150, 50, "black"); //Création du contour.
contour.makeVisible ();
ampoule = new Circle (155, 155, 40, "green"); //Création de l'ampoule.
ampoule.makeVisible ();
x = 150; y = 150; size = 40; //Position et taille par défaut du spot.
}
public Spot (int x, int y, int size, String color) {
contour = new Square (x, y, size, "black"); //Surcharge du constructeur.
ampoule = new Circle (x + 5, y + 5, size - 10, color);
contour.makeVisible();
ampoule.makeVisible ();
this.x = x; this. y = y; this.size = size;
}
public Spot (String color) {
contour = new Square (150, 150, 50, "black"); //Autre surcharge.
ampoule = new Circle (155, 155, 40, color);
}
public void allumer () {
if (ampoule.getColor().equals ("black")) { //Allume l'ampoule et la met verte.
ampoule.setColor ("green");
}
}
public void eteindre () {
if (!ampoule.getColor().equals ("black")) { //On met l'ampoule noire.
ampoule.setColor ("black");
}
}
public void move (int newX, int newY) { //Déplace le spot.
contour.moveTo (newX, newY);
ampoule.moveTo (newX + 5, newY + 5);
x = newX; y = newY;
}
public void resize (int newSize) { //Change la taille du spot.
contour.changeSize (newSize);
ampoule.changeSize (newSize - 10);
}
public void changeColor (String newColor) {
ampoule.setColor (newColor); //Change la couleur du spot.
}
public int getSize () { //Renvoie les informations nécessaires pour les autres classes.
return contour.getSize ();
}
public String getColor () {
return ampoule.getColor ();
}
}

La classe FeuDeSignalisation :
Code : Java
public class FeuDeSignalisation 
{
private Spot bas, milieu, haut; //3 spots. (feu vert, orange et rouge)
private int x, y;
private int size;
private String color;
private static final int TEMPS_ORANGE = 2000; //Temps que dure le feu orange.
public FeuDeSignalisation () {
haut = new Spot (150, 50, 50, "black"); //Création de trois spot.
milieu = new Spot (150, 100, 50, "black");
bas = new Spot (150, 150, 50, "green");
x = 150; y = 50; size = 50; color= "green"; //Position et couleur du feu par défaut.
}
public FeuDeSignalisation (int x, int y, int size) { //Surcharge du constructeur.
haut = new Spot (x, y, size, "black");
milieu = new Spot (x, y + size, size, "black");
bas = new Spot (x, y + 2 * size, size, "green");
this.x = x; this.y = y; this.size = size; color = "green";
}
public void setRed () { //Met le feu au rouge.
if (!haut.getColor().equals ("red")) {
bas.eteindre (); //On éteint le feu vert et on passe à l'orange.
milieu.changeColor ("orange");
//Square tmp = new Square (300, 300, 100, "white");
//tmp.makeVisible ();
//tmp.slowMoveHorizontal (TEMPS_ORANGE);
try {
Thread.sleep (TEMPS_ORANGE);
} catch (Exception e) { }
milieu.eteindre (); //On éteint le feu orange et ou passe au rouge.
haut.changeColor ("red");
color = "red";
}
}
public void setGreen () {
if(!bas.getColor().equals ("green")) {
haut.eteindre (); //Met le fue au vert.
bas.changeColor ("green");
color = "green";
}
}
public void move (int newX, int newY) {
haut.move (newX, newY); //Déplace le feu.
milieu.move (newX, newY + size);
bas.move (newX, newY + 2 * size);
x = newX; y = newY;
}
public void resize (int newSize) {
haut.resize (newSize); //Change le feu de taille.
milieu.resize (newSize);
bas.resize (newSize);
milieu.move (x, y + newSize);
bas.move (x, y + 2 * newSize);
size = newSize;
}
public String getColor () {
return color; //Renvoie les informations nécessaires pour les autres classes.
}
}

Et enfin la classe Carrefour :
Code : Java
/**
* Write a description of class Carrefour here.
*
* @author (your name)
* @version (a version number or a date)
*/

public class Carrefour
{
private FeuDeSignalisation feuVertical, feuHorizontal; //Deux feux pour chacune des rues.
private Rect rueVerticale, rueHorizontale;
public Carrefour () {
feuVertical = new FeuDeSignalisation (60, 70, 20); //Création des feux.
feuHorizontal = new FeuDeSignalisation (150, 200, 20);
rueVerticale = new Rect (0, 150, 300, 40, "gray"); //Création des rues.
rueVerticale.makeVisible ();
rueHorizontale = new Rect (100, 0, 40, 300, "gray");
rueHorizontale.makeVisible ();
feuVertical.setRed ();
}
public void change () {
if (feuVertical.getColor().equals("green")) {
feuVertical.setRed ();
//Alterne les feux, si l'un est vert, on met l'autre au rouge et vis versa.
feuHorizontal.setGreen ();
} else {
feuHorizontal.setRed ();
feuVertical.setGreen ();
}
}
}

Remarque : j'ai utiliser une classe Rect pour dessiner les rues, elle est pas compliquée à réaliser, il faut juste rajouter une variable et modifier un peu les méthodes, je vous la met ici.
N'utiliser pas Rectangle comme nom de classe car elle existe déjà dans le projet!

Code : Java
import java.awt.*;
 
public class Rect
{
private int width;
private int height;
private int xPosition;
private int yPosition;
private String color;
private boolean isVisible;
 
/**
* Create a new square at default position with default color.
*/

public Rect()
{
width = 50;
height = 30;
xPosition = 60;
yPosition = 50;
color = "red";
isVisible = false;
}
public Rect (int x, int y, int width, int height, String color) {
xPosition = x;
yPosition = y;
this.color = color;
this.width =width;
this.height = height;
isVisible = false;
}
/**
* Make this square visible. If it was already visible, do nothing.
*/

public void makeVisible()
{
isVisible = true;
draw();
}

/**
* Make this square invisible. If it was already invisible, do nothing.
*/

public void makeInvisible()
{
erase();
isVisible = false;
}

/**
* Move the square a few pixels to the right.
*/

public void moveRight()
{
moveHorizontal(20);
}
 
/**
* Move the square a few pixels to the left.
*/

public void moveLeft()
{
moveHorizontal(-20);
}
 
/**
* Move the square a few pixels up.
*/

public void moveUp()
{
moveVertical(-20);
}
 
/**
* Move the square a few pixels down.
*/

public void moveDown()
{
moveVertical(20);
}
 
/**
* Move the square horizontally by 'distance' pixels.
*/

public void moveHorizontal(int distance)
{
erase();
xPosition += distance;
draw();
}
 
/**
* Move the square vertically by 'distance' pixels.
*/

public void moveVertical(int distance)
{
erase();
yPosition += distance;
draw();
}
 
/**
* Slowly move the square horizontally by 'distance' pixels.
 
*/

public void slowMoveHorizontal(int distance)
{
int delta;
 
if(distance < 0)
{
delta = -1;
distance = -distance;
}
else
{
delta = 1;
}
 
for(int i = 0; i < distance; i++)
{
xPosition += delta;
draw();
}
}
 
/**
* Slowly move the square vertically by 'distance' pixels.
*/

public void slowMoveVertical(int distance)
{
int delta;
 
if(distance < 0)
{
delta = -1;
distance = -distance;
}
else
{
delta = 1;
}
 
for(int i = 0; i < distance; i++)
{
yPosition += delta;
draw();
}
}
 
/**
* Change the size to the new size (in pixels). Size must be >= 0.
*/

public void changeSize(int newW, int newH)
{
erase();
width = newW;
height = newH;
draw();
}
 
/**
* Change the color. Valid colors are "red", "yellow", "blue", "green",
* "magenta" and "black".
*/

public void changeColor(String newColor)
{
color = newColor;
draw();
}
 
/*
* Draw the square with current specifications on screen.
*/

private void draw()
{
if(isVisible) {
Canvas canvas = Canvas.getCanvas();
canvas.draw(this, color,
new Rectangle(xPosition, yPosition, width, height));
canvas.wait(10);
}
}
 
/*
* Erase the square on screen.
*/

private void erase()
{
if(isVisible) {
Canvas canvas = Canvas.getCanvas();
canvas.erase(this);
}
}
public void moveTo (int x, int y) {
this.xPosition = x;
this.yPosition = y;
draw ();
}
public int getLarg () {
return width;
}
public int detLong () {
return height;
}
}




Il y a donc trois type de liens (composition, agrégation et dépendance) qui permettrons la communication entre les objets.



Chapitre précédent     Sommaire     Chapitre suivant



Rédigé par Lo



Hébergeur du site : 1and1.fr



Site de création de Jeux Vidéo
Apprenez à créer vos propres Jeux Video

A propos de la construction du site...
373009 pages ont été consultées sur le site !
Dont 262 pages pendant les 24 dernières heures.

Page générée en 2.025 secondes


Nos partenaires
- Otium Production : Aide aux débutants à créer leurs jeux
- A.C.S.E.L. : Club de patinage artistique de Caen


  © 2005-2009 www.jeux-libres.com - Toute reproduction totale ou partielle du contenu de ce site est strictement interdite.