Devoir Surveillé

Partie A - Langage de modélisation UML Question 1 - Diagramme de cas d'utilisation Un diagramme de cas d'utilisation modélise les interactions entre les utilisateurs (acteurs) et le système. Étant donné l'impossibilité de tracer informatiquement des figures sur ce support, voici la transcription exacte des éléments qui doivent figurer sur votre diagramme.

D'après le document Devoir Surveillé

Cet article a été rédigé automatiquement à partir du document source, puis vérifié avant publication.

Devoir Surveillé

Document source

Devoir Surveillé

Modélisation et Programmation Objet · PDF · 3 pages · 2017

Afficher l'aperçu du document

Consulter le document original →

Partie A - Langage de modélisation UML

Question 1 - Diagramme de cas d'utilisation

Un diagramme de cas d'utilisation modélise les interactions entre les utilisateurs (acteurs) et le système. Étant donné l'impossibilité de tracer informatiquement des figures sur ce support, voici la transcription exacte des éléments qui doivent figurer sur votre diagramme.

Acteurs identifiés :

  • Administrateur (Acteur principal)
  • Entraineur (Acteur principal)
  • Entraineur du club adverse (Ce rôle peut être fusionné avec "Entraineur" ou modélisé comme un acteur héritant d'Entraineur, interagissant lors de la demande de match)
  • Joueur (Acteur principal)

Associations entre Acteurs et Cas d'utilisation :

Acteur Cas d'utilisation associés
Administrateur - Ajouter un joueur<br>- Mettre à jour un joueur<br>- Supprimer un joueur<br>- Ajouter un tournoi<br>- Ajouter un match<br>- Traiter une demande de match<br>- Visualiser les données sur un tournoi (avec matchs)
Entraineur - Visualiser les données sur un tournoi (avec matchs)<br>- Proposer un match
Entraineur adverse - Répondre à une demande de disponibilité (Confirmer disponibilité)
Joueur - Visualiser les données sur un tournoi (avec matchs)

Note sur le diagramme : Le cas d'utilisation "Visualiser les données sur un tournoi (avec matchs)" étant commun aux trois acteurs (Administrateur, Joueur, Entraineur), vous pouvez modéliser un acteur général "Utilisateur" regroupant ce cas, dont héritent les trois acteurs spécifiques, afin d'alléger le diagramme.

Question 2 - Diagramme d'activités

Le diagramme d'activités détaille le processus « Traitement d'une demande de match ». Il est recommandé d'utiliser des couloirs d'activités (swimlanes) pour montrer la responsabilité de chaque acteur.

Couloirs (Partitions) :

  1. Entraineur (Demandeur)
  2. Administrateur
  3. Entraineur adverse

Déroulement séquentiel des actions :

  1. [Nœud initial] placé dans le couloir de l'Entraineur.
  2. Action 1 (Entraineur) : "Envoyer une demande avec le nom du club adverse".
  3. Transition vers Administrateur.
  4. Action 2 (Administrateur) : "Recevoir la demande et contacter l'entraineur adverse".
  5. Transition vers Entraineur adverse.
  6. Action 3 (Entraineur adverse) : "Confirmer sa disponibilité" (Génère une réponse Favorable ou Défavorable).
  7. Transition vers Administrateur.
  8. Nœud de décision (Losange) : Évaluation de la réponse de l'entraineur adverse.
    • Branche [Réponse Favorable] :
      • Action 4a (Administrateur) : "Enregistrer un nouveau match".
      • Action 5a (Système/Administrateur) : "Envoyer une notification automatique aux deux entraineurs".
      • Transition vers le [Nœud final].
    • Branche [Réponse Défavorable] :
      • Action 4b (Système/Administrateur) : "Envoyer un message de refus à l'entraineur demandeur".
      • Transition vers le [Nœud final].

Question 3 - Diagramme de classes d'analyse

Remarque : L'énoncé mentionne une « figure 1 - Diagramme de classes d'analyse à compléter » qui est absente du document source fourni. La conception ci-dessous reconstitue logiquement le diagramme de classes complet sur la base des règles de gestion dictées par le texte.

Classes et Attributs :

  • Membre : Identifiant (ID), nom, prenom.
  • Joueur (hérite de Membre) : taille, poids.
  • Entraineur (hérite de Membre) : anneesExperience.
  • Club : code.
  • Tournoi : numeroUnique, nom, dateDebut, dateFin, adresse, type.
  • Match : numeroUnique, date, duree.
  • HistoriqueJoueur (Classe-association entre Joueur et Club) : periode, salaire.

Relations et Multiplicités :

  1. Héritage : Joueur et Entraineur héritent de la classe mère abstraite Membre.
  2. Association Joueur - Club (Jouer dans) :
    • Un Joueur joue dans un à plusieurs clubs durant sa carrière : 1..* (côté Club).
    • Un Club contient au maximum 29 joueurs : 0..29 (côté Joueur).
    • Classe-association : Le texte indique "durant sa carrière... pendant une période de temps et avec un salaire bien déterminé". Ces informations (période, salaire) ne dépendent ni du joueur seul, ni du club seul, mais de la relation historique entre les deux. Il faut donc une classe-association liée à cette relation.
  3. Association Entraineur - Club (Diriger/Entrainer) :
    • Un Club a un seul entraineur : 1..1 (côté Entraineur).
    • Un Entraineur entraîne un club (à la fois) : 0..1 ou 1..1 (côté Club).
  4. Association Tournoi - Match (Contenir) :
    • Un Tournoi contient plusieurs matchs : 1..* (côté Match).
    • Un Match appartient à un tournoi : 1..1 (côté Tournoi).

Partie B - JAVA

Note préliminaire : Les règles exigent que le code soit exécutable. L'énoncé précise que Joueur a ses getters/setters implémentés et que la classe Entraineur est déjà implémentée. Pour garantir la compilation du code ci-dessous (règle 4), une implémentation minimale de Entraineur est incluse, et les attributs de Membre sont déclarés protected pour permettre l'accès par héritage et au sein du même paquet.

Question I - Implémentation de la classe Membre

public class Membre {
    // Déclarés en protected pour être accessibles par les classes filles (Joueur, Entraineur)
    protected int id;
    protected String nom;
    protected String prenom;

    // Uniquement un constructeur paramétré
    public Membre(int id, String nom, String prenom) {
        this.id = id;
        this.nom = nom;
        this.prenom = prenom;
    }

    // Getters et Setters uniquement pour l’attribut identifiant
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    // La méthode toString
    @Override
    public String toString() {
        return "ID: " + id + ", Nom: " + nom + ", Prénom: " + prenom;
    }

    // La méthode equals
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Membre membre = (Membre) o;
        // Deux membres sont égaux s’ils ont le même identifiant et le même nom
        return this.id == membre.id && 
               this.nom != null && 
               this.nom.equals(membre.nom);
    }
}

Question II - Implémentation de la classe Joueur

public class Joueur extends Membre {
    private float taille;
    private float poids;

    public Joueur(int id, String nom, String prenom, float taille, float poids) {
        super(id, nom, prenom); // Appel du constructeur de la classe mère
        this.taille = taille;
        this.poids = poids;
    }

    // Les getters et setters sont supposés implémentés selon l'énoncé
    public float getTaille() { return taille; }
    public void setTaille(float taille) { this.taille = taille; }
    
    public float getPoids() { return poids; }
    public void setPoids(float poids) { this.poids = poids; }

    @Override
    public String toString() {
        return super.toString() + ", Taille: " + taille + ", Poids: " + poids;
    }
}

Code additionnel pour la compilation des parties suivantes, modélisant la classe Entraineur mentionnée comme "déjà implémentée" par l'énoncé :

public class Entraineur extends Membre {
    private int anneesExperience;

    public Entraineur(int id, String nom, String prenom, int anneesExperience) {
        super(id, nom, prenom);
        this.anneesExperience = anneesExperience;
    }
}

Question III - Implémentation de la classe Club et de l'Exception

Afin que l'exception personnalisée demandée à la question III.6 puisse être compilée, nous devons d'abord la définir.

public class PoidsException extends Exception {
    public PoidsException(String message) {
        super(message);
    }
}

Voici l'implémentation complète de la classe Club, intégrant les 6 sous-questions.

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Club {
    private String code;
    private List<Membre> membres;

    public Club(String code) {
        this.code = code;
        this.membres = new ArrayList<>();
    }

    // 1. La méthode ajouter
    public void ajouter(Membre membre) {
        // Un membre ne peut être affecté deux fois (utilise la méthode equals de Membre)
        if (membres.contains(membre)) {
            return;
        }

        // Vérification des contraintes selon le type de membre
        if (membre instanceof Entraineur) {
            // Un club ne peut contenir qu'un seul entraineur
            for (Membre m : membres) {
                if (m instanceof Entraineur) {
                    System.out.println("Opération refusée : Le club possède déjà un entraineur.");
                    return; 
                }
            }
        } else if (membre instanceof Joueur) {
            // Un club peut contenir au maximum 29 joueurs (contrainte textuelle de la partie A)
            int compteurJoueurs = 0;
            for (Membre m : membres) {
                if (m instanceof Joueur) {
                    compteurJoueurs++;
                }
            }
            if (compteurJoueurs >= 29) {
                System.out.println("Opération refusée : Le club a atteint sa limite de 29 joueurs.");
                return;
            }
        }
        
        membres.add(membre);
    }

    // 2. La méthode supprimer
    public void supprimer(Membre membre) {
        membres.remove(membre);
    }

    // 3. La méthode toString (code du club et uniquement la liste de ses Joueurs)
    @Override
    public String toString() {
        StringBuilder description = new StringBuilder();
        description.append("Code du Club: ").append(code).append("\nListe des joueurs:\n");
        
        for (Membre m : membres) {
            if (m instanceof Joueur) {
                description.append(m.toString()).append("\n");
            }
        }
        return description.toString();
    }

    // 4. La méthode afficherTailles (affiche uniquement les tailles des joueurs)
    public void afficherTailles() {
        for (Membre m : membres) {
            if (m instanceof Joueur) {
                Joueur j = (Joueur) m;
                System.out.println("Taille: " + j.getTaille());
            }
        }
    }

    // 5. La méthode supprimerJoueurs par nom
    public void supprimerJoueurs(String nom) {
        // L'utilisation d'un Iterator est indispensable pour supprimer des éléments 
        // d'une collection tout en la parcourant, évitant ainsi une ConcurrentModificationException.
        Iterator<Membre> it = membres.iterator();
        while (it.hasNext()) {
            Membre m = it.next();
            // L'attribut 'nom' est accessible ici car il a été déclaré 'protected' dans Membre
            if (m instanceof Joueur && m.nom != null && m.nom.equals(nom)) {
                it.remove();
            }
        }
    }

    // 6. La méthode moyennePoids
    public float moyennePoids() throws PoidsException {
        float sommePoids = 0;
        int nombreJoueurs = 0;

        for (Membre m : membres) {
            if (m instanceof Joueur) {
                sommePoids += ((Joueur) m).getPoids();
                nombreJoueurs++;
            }
        }

        if (nombreJoueurs == 0) {
            return 0.0f;
        }

        float moyenne = sommePoids / nombreJoueurs;

        if (moyenne > 80.0f) {
            throw new PoidsException("Poids des joueurs trop élevé");
        }

        return moyenne;
    }
}

Méthode

Face à ce type de devoir surveillé, la réussite repose sur la lecture rigoureuse des consignes et la compréhension des liens invisibles entre les questions :

  1. Repérage des contraintes cardinales en UML : Dès la lecture du texte introductif, encadrez les mots exprimant des quantités ("au maximum 29 joueurs", "un seul entraineur", "plusieurs clubs"). Ces mots dictent les multiplicités de votre diagramme de classes et se traduisent plus tard directement par des conditions if dans votre code (comme dans la méthode ajouter() de la classe Club).
  2. Identification des héritages : Quand le texte dit "Un membre est caractérisé par... Un joueur par... Un entraineur par...", il décrit une structure d'héritage classique. En Java, cela implique l'utilisation du mot-clé extends et le bon paramétrage de l'appel super() dans le constructeur de la classe fille.
  3. Respect strict des conventions (Encapsulation) : L'énoncé précise "Les Getters et les Setters ne sont à implémenter que si leur demande est explicite". C'est un piège classique de conception. Il vous interdit de créer un getNom() dans Membre. Par conséquent, pour accéder au nom dans supprimerJoueurs(String nom) de la classe Club, l'attribut nom doit avoir une portée (visibilité) protected ou package-private, et non private.
  4. Gestion des collections en Java : Lorsqu'on vous demande de supprimer des éléments d'une liste sous une certaine condition (Question III.5), il est déconseillé d'utiliser une boucle for ou un foreach, car modifier une liste pendant son parcours déclenche une erreur d'exécution (ConcurrentModificationException). Le réflexe doit être l'utilisation de l'objet Iterator.

Partager

Commentaires

Aucun commentaire pour le moment. Posez la première question.

Les commentaires sont relus avant publication. Votre e-mail n'est jamais affiché.

← Toutes les révisions