Examen 2024-25

1. Mise en œuvre de modèles de conception

Pour mettre en œuvre en Java la classe Person à partir d’un modèle de conception UML, Alice a suivi une stratégie de mise en œuvre qui fait appel à l’approche Accesseur/Mutateur, aussi connue comme Getter/Setter. Le Listing suivant présente le résultat de sa mise en œuvre.[1]

Listing 1. La classe Person
public class Person {
    private String name;
    private static final String NAME_INITIAL_VALUE = "John Doe";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        if (null == name) throw new NullPointerException("Name must not be null");

        this.name = name;
    }

    public void resetName() {
        this.name = NAME_INITIAL_VALUE;
    }

    public boolean isNameSet() {
        return !NAME_INITIAL_VALUE.equals(name);
    }
}

Aidez Alice à réfuter la proposition de Bob en énumérant les avantages de la programmation défensive pour la méthode setName().`

Solution
  • Il s’agit d’une méthode publique, ce qui veut dire que Alice ne peut pas contrôler les classes clientes de cette méthode. Imposer des pré-conditions aux clientes actuelles et futures de cette méthode n’est pas vraiment envisageable.

  • Tout comme la programmation assertive, le but de la programmation défensive est de vérifier toutes les entrées d’une méthode pour assurer son fonctionnement. Contrairement à la programmation assertive, les erreurs n’arrêtent pas l’exécution du programme et peuvent être traitées par les classes clientes.

  • Les assertions sont des prédicats qui vérifient des conditions qui ne doivent jamais se produire. Ici, l’appel de la méthode setName() avec un argument nul peut se produire.

1.1. Refactorings

Carol, la chef de Alice, n’a pas apprécié son choix et lui demande de réécrire la classe \code{Person} en adoptant cette fois une approche Classes-Enveloppe. Pour s’assurer que le nouveau code préserve le comportement visible de l’ancien, Alice a commencé à établir une suite d’opérations de refactoring, qu’elle appliquera à son code initial.

Elle a déjà établi les 3 premières étapes :

  1. Ajouter la classe NameWrapper (refactoring AddEntity)

  2. Renommer le champ name en value (RenameEntity)

  3. Ajouter un champ privé name de type NameWrapper à la classe Person et l’initialiser à new NameWrapper() (Add Entity)

  4. (…​)

Aidez Alice à compléter sa suite d’opérations

Solution
  1. Ajouter la classe NameWrapper (refactoring AddEntity)

  2. Renommer le champ name en value (RenameEntity)

  3. Ajouter un champ privé name de type NameWrapper à la classe Person et l’initialiser à new NameWrapper() (Add Entity)

  4. Modifier la visibilité du champ NAME_INITIAL_VALUE à package (Change visibility)

  5. Déplacer le champ NAME_INITIAL_VALUE à la classe NameWrapper (Move static field)

  6. Modifier la visibilité du champ value en package (Change Visibility)

  7. Déplacer le champ value à la classe NameWrapper (Move Instance Field);

  8. Déplacer la méthode getName() à la classe NameWrapper (Move Instance Method)

  9. Déplacer la méthode setName() à la classe NameWrapper (Move Instance Method)

  10. Déplacer la méthode resetName() à la classe NameWrapper (Move Instance Method)

  11. Déplacer la méthode isSetName() à la classe NameWrapper (Move Instance Method)

  12. Modifier la visibilité du champ value en private (Change Visibility)

Donnez le code des classes Person et NameWrapper, après les refactorings :

Solution
Listing 2. La classe Person (après refactoring)
public class Person {
    private NameWrapper name = new NameWrapper();

    public String getName() {
        return name.getName();
    }

    public void setName(String name) {
        this.name.setName(name);
    }

    public void resetName() {
        this.name.resetName();
    }

    public boolean isNameSet() {
        return this.name.isNameSet();
    }
}
Solution
Listing 3. La classe NameWrapper
public class NameWrapper {
    static final String NAME_INITIAL_VALUE = "John Doe";
    private String value;

    public String getName() {
        return value;
    }

    public void setName(String name) {
        if (null == name) throw new NullPointerException("Name must not be null");
        value = name;
    }

    public void resetName() {
        value = NAME_INITIAL_VALUE;
    }

    public boolean isNameSet() {
        return !NAME_INITIAL_VALUE.equals(value);
    }
}

1. Comme vous pouvez remarquer, Alice n’est pas férue de commentaires !