Contrôle continu 2025-26
1. Techniques de codage
L’objectif de cet exercice est d’implémenter la classe ImmutableRGB,
qui représente l’encodage de couleur "rouge-vert-bleu". Dans cet
encodage, chacune des couleurs peut avoir une valeur entre 0 et 255. La
spécification de cette classe est donnée par le diagramme de classes UML
présenté dans la figure ci-dessous.
Pour l’implémenter, vous devez respecter les règles suivantes :
-
La classe est immuable ;
-
Les valeurs nulles ne sont pas acceptées ;
-
La classe doit redéfinir la méthode
Object::equals(Object);
1.1. Signature de la classe
Commencez par déclarer la signature de la classe, sans spécifier son corps (son contenu) :
Solution
public final class ImmutableRGB {} (1)
-
Le mot-clé
finalest obligatoire ici.
1.2. Champs
Déclarez maintenant les champs de la classe :
Solution
final private short red;
final private short green;
final private short blue;
final private String name;
-
Tous les attributs doivent être déclarés
final
1.3. Constructeur
Déclarez le constructeur de la classe :
Solution
public ImmutableRGB(short red, short green, short blue, @NotNull String name) {
if (name == null || red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255) {
throw new IllegalArgumentException();
}
this.red = red;
this.green = green;
this.blue = blue;
this.name = name;
}
-
En Java, les types primitifs ne peuvent pas avoir une valeur nulle ;
-
L’utilisation d’une garde est nécessaire.
1.4. La méthode invert()
Déclarez la méthode
invert(). Cette méthode rend un nouvel encodage, qui correspond à l’inverse de l’objet. L’inverse d’une couleur correspond à son complément à 255. Par exemple, l’inverse de l’encodage(r=0,b=255,g=100)est(r=255,b=0,g=155)
Solution
public ImmutableRGB invert() {
return new ImmutableRGB((short) (255 - red), (short) (255 - green), (short) (255 - blue), "Inverse of " + name);
}
-
L’argument
namepeut avoir n’importe quelle valeur, à part la valeur nulle -
La création d’une nouvelle instance est obligatoire.
1.5. Égalité
Déclarez la méthode
equals():
Solution
public boolean equals(Object o) {
if (!(o instanceof ImmutableRGB that)) return false;
return red == that.red && green == that.green && blue == that.blue && name.equals(that.name);
}
1.6. Accesseurs
Déclarez le ou les accesseurs des champs :
Solution
public String getName() {
return name;
}
1.7. Explications sur l’implémentation d’une classe immuable
Expliquez comment votre code assure que les objets de cette classe sont immuables :
Solution
-
La classe est déclarée
final: elle ne doit pas pouvoir être héritée. -
Les champs non transitoires sont déclarés
privateetfinal
1.8. Explication sur les champs
Expliquez comment votre code assure que les champs ne contiennent pas de valeurs nulles et comparez votre solution avec les alternatives vues en cours.
Solution
-
Les types de base de Java, comme
shortici, ne peuvent pas avoir une valeur nulle -
Le constructeur utilise une garde pour empêcher les instances de cette classe d’avoir des valeurs invalides.
-
Les annotations sont utiles pour trouver des erreurs pendant la compilation, mais ne peuvent pas empêcher des utilisations incorrectes.
-
Les assertions ne sont pas souhaitables ici, car il s’agit d’un constructeur public et que l’on ne peut pas connaître à l’avance la valeur des arguments passés au constructeur.
1.9. Méthode de test
Écrivez une méthode de test JUnit capable de tester la méthode
ImmutableRGB::invert().
Solution
@Test
void invert() {
ImmutableRGB actual = new ImmutableRGB((short) 0, (short)255, (short) 100, "actual");
ImmutableRGB expected = new ImmutableRGB((short) 255, (short)0, (short)155, "Inverse of actual");
assertEquals(expected, actual.invert());
}
-
Le nom attendu dépend de l’implémentation de la méthode
invert()
2. Le patron Décorateur
Considérez la classe Character, qui représente un personnage de jeu de
rôles et dont le code source Java est le suivant :
public class Character {
private String name;
private int life;
private Point position;
private int currentHP;
private int intellect;
private int strength;
public int attack() {
return strength * life/100;
}
public int defend() {
return intellect * life/100;
}
public void receiveHit(int intensity){
life = life - intensity;
}
public boolean isAlive() {
return life > 0;
}
public int getLife() {
return life;
}
public String getName() {
return name;
}
}
On souhaite faire évoluer cette mise en œuvre pour permettre la gestion
d’équipements, comme un bouclier ou une épée, qui modifient le
comportement d’un personnage. Pour ce faire, nous allons utiliser le
patron de conception Décorateur. Proposez une solution (une
instance du patron Décorateur) permettant la gestion de deux
équipements : les boucliers et les épées. Le bouclier doit multiplier
par 3 la force de défense, c’est à dire, le résultat de la méthode
defend(). L’épée doit multiplier par 5 la force d’attaque , c’est à
dire, le résultat de la méthode attack(). Le bouclier et l’épée
peuvent être utilisés par n’importe quel personnage.
2.1. Le composant
Tout d’abord, implémentez l’interface ou la classe abstraite jouant le rôle de Composant :
Solution
public interface Character {
int attack();
int defend();
void receiveHit(int intensity);
boolean isAlive();
int getLife();
String getName();
}
2.2. Le décorateur Bouclier
Maintenant, implémentez la classe jouant le rôle de Décorateur pour le comportement d’un Bouclier :
Solution
public class ShieldDecorator implements Character {
private final Character character;
public ShieldDecorator(Character character) {
this.character = character;
}
@Override
public int defend() {
return character.defend() * 3;
}
@Override
public int attack() {
return character.attack();
}
@Override
public void receiveHit(int intensity) {
character.receiveHit(intensity);
}
@Override
public boolean isAlive() {
return character.isAlive();
}
@Override
public int getLife() {
return character.getLife();
}
@Override
public String getName() {
return character.getName();
}
}
2.3. Le décorateur Épée
Enfin, implémentez la classe jouant le rôle de Décorateur pour le comportement d’une Épée :
Solution
public class SwordDecorator implements Character {
private final Character character;
public SwordDecorator(Character character) {
this.character = character;
}
@Override
public int attack() {
return character.attack() * 5;
}
@Override
public int defend() {
return character.defend();
}
@Override
public void receiveHit(int intensity) {
character.receiveHit(intensity);
}
@Override
public boolean isAlive() {
return character.isAlive();
}
@Override
public int getLife() {
return character.getLife();
}
@Override
public String getName() {
return character.getName();
}
}