Contrôle continu 2023-24
1. Techniques de programmation
La classe ArrayList, présentée ci-dessous, combine deux techniques de programmation différentes~: défensive et assertive.
Basez-vous sur cet exemple pour répondre aux questions suivantes.
public class ArrayList<E> {
private E[] data;
private int size = 0;
public ArrayList(int initialSize) {
data = (E[]) (new Object[initialSize]);
}
public E get(int index) {
if (index < 0 || index >= size) throw new IndexOutOfBoundsException();
return resolve(index);
}
private E resolve(int index) {
assert index < size && index >= 0;
assert data != null;
return data[index];
}
public void add(@Nonnull E element) {
ensureCapacity();
data[size++] = element;
}
private void ensureCapacity() {
if (size == data.length) {
E[] oldData = data;
data = (E[]) (new Object[size * 2]);
System.arraycopy(oldData, 0, data, 0, size);
}
}
}
1.1. Programmation défensive
Expliquez les principes de la programmation défensive
Solution
La programmation défensive est une technique de développement de code maintenable.
-
Elle garantit que le code se comporte de manière correcte, en dépit d’une entrée incorrecte.
-
Elle garantit qu’une méthode ne peut être exécutée que si certaines conditions sont remplies.
1.2. Gardes
A votre avis, quel était l’objectif du développeur lorsqu’il a ajouté une garde à la méthode
get()?
Solution
L’objectif du développeur est d’empêcher que le tableau soit accédé avec un index invalide (inférieur à zéro ou égal ou supérieur à la taille du tableau)
1.3. Programmation assertive
Expliquez les principes de la programmation assertive.
Solution
-
C’est une technique qui suit le principe de l’échec rapide et visible.
-
Elle empêche de propagation d’erreurs dans le code : l’exécution s’arrête à l’endroit de l’erreur.
-
Elle empêche le système de rentrer dans un état incohérent en raison des éventuels changements dans le code source.
1.4. Assertions
A votre avis, quel était l’objectif du développeur lorsqu’il a ajouté deux assertions à la méthode
resolve()?
Solution
-
Le développeur utilise ces assertions pour deux raisons:
-
Il veut s’assurer que si cette classe est modifiée, les appelants de la méthode
resolve()continueront à respecter ses pré-conditions, c’est dire, que l’index est valable et que le tableau a bien été initialisé. -
Il veut rendre plus lisible la méthode
resolve(), les assertions expliquent ce que cette méthode attend avant d’être appelée.
-
-
Notez que le code actuel respecte bien les pré-conditions de la méthode
resolve(): les assertions empêchent l’impossible.
1.5. Annotations
Le paramètre
element. Quelle est l’utilité de cette annotation ? Quel est son impact sur l’exécution de la méthode ?de la méthode `add()utilise l'annotation `@Nonnull
Solution
-
Cette annotation permet aux outils d’analyse statique de code et à certains IDEs de vérifier que la méthode
add()n’est pas appelée avec des arguments nuls. -
L’annotation n’a aucun impact sur l’exécution.
2. Patrons de conception
2.1. Poids mouche
Dans quel contexte il est conseillé d’utiliser le patron "Poids plume" (Flyweight) ? Donnez des exemples de son utilisation.
Solution
-
On utilise le patron poids mouche lors qu’on a besoin d’instancier beaucoup de petits objets et que l’on souhaite réduire l’empreinte mémoire.
-
La classe
java.lang.Integerutilise ce patron pour limiter le nombre d’instances.
2.2. Singleton
Quel est l’objectif principal du patron de conception "Singleton" ? Dans quels cas est-il approprié de l’utiliser ?
Solution
-
L’objectif du patron singleton est d’assurer qu’une classe n’a qu’une seule instance et fournir un point d’accès global à cette instance et aussi lorsqu’on souhaite l’instancier de manière paresseuse.
-
On l’utilise lorsqu’il ne doit y avoir qu’une seule instance d’une classe, et elle doit être accessible aux clients à partir d’un point d’accès bien connu et lorsque cette unique instance doit être extensible par sous-classe et que les clients doivent être en mesure d’utiliser une instance d’une sous-classe sans modifier leur code
2.3. 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, autrement dit, le résultat de la méthode attack().
Le bouclier et l’épée peuvent être utilisés par n’importe quel personnage.
Solution
-
Le patron décorateur a besoin d’une classe abstraite ou une interface, les décorateurs ne peuvent pas être des sous-classes de la classe
Character. -
Première étape, ajout d’une interface appelée
ICharacter(le nom n’est pas important), la classeCharacterdoit implémenter cette interface.package fr.unantes.sce.patterns.decorator; public interface Character { int attack(); int defend(); void receiveHit(int intensity); boolean isAlive(); int getLife(); String getName(); } -
Deuxième étape, ajout d’un décorateur abstrait. Cette classe n’est pas obligatoire, mais elle permet de réduire le nombre de lignes de code.
package fr.unantes.sce.patterns.decorator; public abstract class AbstractDecorator implements Character { protected Character character; public AbstractDecorator(Character character) { this.character = character; } @Override public int attack() { return character.attack(); } @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(); } } -
Troisième étape, le décorateur bouclier.
package fr.unantes.sce.patterns.decorator; public class ShieldDecorator extends AbstractDecorator implements Character { public ShieldDecorator(Character character) { super(character); } @Override public int defend() { return character.defend() * 3; } } -
Dernière étape, le décorateur épée.
package fr.unantes.sce.patterns.decorator; public class SwordDecorator extends AbstractDecorator implements Character { public SwordDecorator(Character character) { super(character); } @Override public int attack() { return character.attack() * 5; } }
3. Traduction de modèles de conception en code Java
Considérez le diagramme de classes UML présenté ci-dessous.
Que représente ce diagramme ? Expliquez le rôle de tous les éléments qui le composent.
Solution
-
Le diagramme représente deux classes,
PersonnageetKart -
La classe
Personnagepossède un attribut,nom, de typeString -
La classe
Kartpossède, elle-aussi, un seul attribut,modèle, de typeString -
Ces deux classes sont reliées par une association bidirectionnelle, sans nom
-
Cette association possède deux rôles,
piloteetkarts -
Le rôle
pilotela relie à la classePersonnageet possède une multiplicité de valeur[0..1].
4. Diagramme d’objets
Dessinez un diagramme d’objets UML représentant l'état final des instances du diagramme de classes précédent, après l’exécution des opérations énumérées ci-dessous :
-
Création de l’instance
Yoshide la classePersonnage -
Création de l’instance
Mariode la classePersonnage -
Création de l’instance
Carrera Quadde la classeKart -
Création de l’instance
City Tripperde la classeKart -
Ajout de
City TripperauxkartsdeYoshi -
Affectation de
Marioen tant quepilotedeCarrera Quad
Solution
-
La notation des diagrammes objet est disponible ici : https://www.uml-diagrams.org/class-diagrams-overview.html#object-diagram
-
Création des instances
-
Ajout de
City TripperauxkartsdeYoshi -
Notation alternative (liens unidirectionnels)
-
Affectation de
Marioen tant quepilotedeCarrera Quad -
Notation alternative (liens unidirectionnels)