IFT232_Exercices_Robots-solution.doc

Le but de cette séance d'exercices est de vous préparer pour l'examen final. ..... //
Meilleure solution : Application du State Design Pattern --> classe abstraite ...

Part of the document


IFT232 Méthodes Orientées Objets Exercices VI Solutionnnaire
Le but de cette séance d'exercices est de vous préparer pour l'examen
final. Voici un exemple partiel d'examen. Vous auriez normalement 3 heures
pour le solutionner sur papier. Dans le cadre de cette séance d'exercices,
vous devez faire les implémentations complètes. Les solutions décrites ici ne sont pas optimales, mais acceptables. La
meilleure solution se trouve dans le fichier .jar.
Étude de cas : Robot Autonome Vous venez de découvrir dans le grenier de vos grands-parents, un robot de
la première génération des robots autonomes. Ces robots pouvaient mener
une vie presque autonome... à condition bien sûr de les programmer
correctement. Le vôtre est déjà programmé en Java, un vieux langage de
programmation certes, mais malgré tout pas si mal foutu. Plein d'espoir, vous commencez à examiner le code du programme, que vous
trouverez ci-dessous. Les classes principales sont Film, Lieu, Marchandise
et Robot. Les classes Film, Lieu, Marchandise représentent en fait des
structures de données passées en arguments aux actions primitives que peut
réaliser un robot. La classe Robot contient les actions primitives. Ces
actions primitives sont encodées sous forme de méthodes : voir(Film) ,
aller(Lieu) , dormir(Lieu, Date), acheter(Marchandise). Des scripts plus
complexes peuvent être aussi spécifiés à l'aide de méthode. La méthode
passerUneBonneSoiree() constitue un exemple d'une action complexe
correspondant è une séquence d'actions primitives. Un robot vieillit et les
actions primitives qu'il peut réaliser sont contraintes par son âge. Un
robot de moins de 13 ans est considéré comme un enfant. Un robot âgé entre
13 et 18 ans comme un adolescent. Un robot âgé de 18 ans et plus comme un
adulte. Après avoir examiné le code existant de près, vous êtes franchement déçu. A
preuve, toutes ces conditionnelles, ce n'est vraiment pas de la
programmation par objets... Le coeur vaillant et plein d'espoir vous
décidez de refactoriser le code afin de le rendre facilement modifiable
pour pouvoir ajouter de nouvelles fonctionnalités à votre robot, en
particulier,
. modifier son comportement en fonction de nouvelles catégories d'âge,
. implémenter de nouvelles actions primitives,
. implémenter la possibilité de réaliser de nouvelles commandes
complexes,
. augmenter son autonomie de décision... Voici les fragments principaux du programme de votre robot. /**
* LA classe Robot
*/
public class Robot {
private GregorianCalendar anniversaire_;
/**
* Méthodes statiques
*/ protected static Robot getRobot(int age) {
GregorianCalendar anniversaire = new GregorianCalendar();
anniversaire.add(GregorianCalendar.YEAR, 0 - age);
return new Robot(anniversaire);
}
public static Robot getEnfant() {return getRobot(5);}
public static Robot getAdolescent() {return getRobot(15);}
public static Robot getAdulte() { return getRobot(25); } /**
* CONSTRUCTEURS
*/ public Robot(GregorianCalendar naissance) {
setAnniversaire(naissance);
} /**
* ACCESSEURS
*/ public int getAge() { ... } public GregorianCalendar getAnniversaire() {return anniversaire_;}
public void setAnniversaire(GregorianCalendar newAnniversaire) {
anniversaire_ = newAnniversaire;
}
public boolean isEnfant() {return getAge() < 13;}
public boolean isAdolescent() {return (!isEnfant()) && getAge() < 18;}
public boolean isAdulte() { return getAge() > 17;} /**
* La méthode viellir() est invoquée à tous les ans à l'anniversaire du
robot;
*/
public void vieillir() {}
public boolean voir(Film unFilm) {
if (isEnfant())
return unFilm.getCategorie() == Film.GENERAL;
if (isAdolescent())
return unFilm.getCategorie() == Film.GENERAL
|| unFilm.getCategorie() == Film.RESTREINT;
if (isAdulte())
return true;
return false;
}
/**
* ACTIONS PRIMITIVES
*/ public boolean acheter(Marchandise objet) {
if (isEnfant())
return objet.isVenteLibre();
if (isAdolescent())
return objet.isVenteLibre();
if (isAdulte())
return true;
return false;
} public boolean aller(Lieu lieu) {
if (isEnfant())
return lieu.isAccesLibre();
if (isAdolescent())
return lieu.isAccesLibre();
if (isAdulte())
return true;
return false;
} public boolean dormir(Lieu lieu, Date heure) {
if (isEnfant())
return lieu.isAccesLibre() && heure.getHours() < 21;
if (isAdolescent())
return lieu.isAccesLibre() && heure.getHours() < 24;
if (isAdulte())
return true;
return false;
}
/**
* ACTIONS COMPLEXES
*/ public boolean passerUneBonneSoiree() {
if (isEnfant()) {
aller(new Lieu("CINEMA", true));
voir(new Film("Harry Potter", Film.GENERAL));
acheter(new Marchandise("Popcorn", true));
dormir(new Lieu("MAISON", true), new Date("21:00:00"));
}
if (isAdolescent()) {
aller(new Lieu("CINEMA", true));
voir(new Film("American Pie", Film.RESTREINT));
acheter(new Marchandise("Popcorn", true));
dormir(new Lieu("MAISON", true), new Date("23:00:00"));
}
if (isAdulte()) {
aller(new Lieu("CINEMA", true));
voir(new Film("Dernier Tango à Paris", Film.ADULTE));
aller(new Lieu("DISCOTHEQUE", false));
acheter(new Marchandise("Biere", false));
dormir(new Lieu("HOTEL", false), new Date("3:00:00"));
}
return true;
}
}
/**
* LA classe FILM
*/ public class Film {
public final static int GENERAL = 0;
public final static int RESTREINT = 12;
public final static int ADULTE = 17;
private java.lang.String titre_;
private int categorie_ = GENERAL;
public Film(String titre, int categorie) {
setTitre(titre);
setCategorie(categorie);
}
public int getCategorie() { return categorie_; }
public void setCategorie(int newCategorie) {categorie_ = newCategorie;
}
public java.lang.String getTitre() { return titre_; }
public void setTitre(java.lang.String newTitre) { titre_ = newTitre; }
} /**
* LA classe LIEU
*/
public class Lieu { private java.lang.String description_;
private boolean accesLibre_ = true;
public Lieu(String description, boolean categorie) {
setDescription(description);
setAccesLibre(categorie);
}
public java.lang.String getDescription() { return description_; }
public void setDescription(java.lang.String newDescription) {
description_ = newDescription;
}
public boolean isAccesLibre() { return accesLibre_; }
public void setAccesLibre(boolean newAccessLibre) {
accesLibre_ = newAccessLibre;
}
} /**
* LA classe Marchandise
*/ public class Marchandise {
private java.lang.String description_;
private boolean venteLibre_ = true;
public Marchandise(String description, boolean categorie) {
setDescription(description);
setVenteLibre(categorie);
}
public java.lang.String getDescription() { return description_;}
public void setDescription(java.lang.String newDescription) {
description_ = newDescription;
}
public boolean isVenteLibre() { return venteLibre_; }
public void setVenteLibre(boolean newVenteLibre) {
venteLibre_ = newVenteLibre;
}
}
Première étape : Refactorisation du code existant
Question 1 : Tests et JUnit (10 pts)
Avant de vous lancer corps et âmes dans la refactorisation de ce programme,
vous devez écrire quelques tests pour vous assurer que le comportement du
programme sera préservé.
a) A l'aide de JUnit, définissez la classe TestRobot.
b) Redéfinissez les méthodes permettant de gérer les fixtures.
c) Implémentez 4 tests unitaires pour tester la méthode voir(Film) de la
classe Robot. public class _Test_Robot extends VajTestCase // TestCase
{ //declaration des variables utilisées dans les fixtures
protected Robot enfant_ = null;
protected Robot adolescent_ = null;
protected Robot adulte_ = null;
protected Film filmEnfant_ = null;
protected Film filmAdolescent_ = null;
protected Film filmAdulte_ = null;
//definitions des méthodes setUp() et tearDown()
// création des valeurs des variables d'instances
// nettoyage en mettant à null les variables d'instance
public void setUp() throws Exception {
enfant_ = Robot.getEnfant(); //new Robot(...)
adolescent_ = Robot.getAdolescent();
adulte_ = Robot.getAdulte();
filmEnfant_ = new Film("Harry Potter", Film.GENERAL);
filmAdolescent_ = new Film("American Pie", Film.RESTREINT);
filmAdulte_ = new