Conception par objet et programmation Java

Partie 1 : Choix multiples Question 1 - Ordre d'exécution des constructeurs Bonne réponse : C. 123 Justification : En Java, lorsqu'on instancie une classe enfant (ici Three ), le constructeur de la classe courante fait systématiquement appel au constructeur de sa classe parente avant d'exécuter son propre code.

D'après le document Conception par objet et programmation Java

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

Conception par objet et programmation Java

Document source

Conception par objet et programmation Java

Programming, Object-Oriented Design · PDF · 8 pages · 2015

Afficher l'aperçu du document

Consulter le document original →

Partie 1 : Choix multiples

Question 1 - Ordre d'exécution des constructeurs

Bonne réponse : C. 123

Justification : En Java, lorsqu'on instancie une classe enfant (ici Three), le constructeur de la classe courante fait systématiquement appel au constructeur de sa classe parente avant d'exécuter son propre code. S'il n'y a pas d'appel explicite via super(...), le compilateur insère un appel implicite super() vers le constructeur sans paramètre de la classe mère.

Ainsi, lors de l'instruction new Three() ; :

  1. Le constructeur de Three est appelé, mais avant d'imprimer "3", il appelle implicitement super() vers Two.
  2. Le constructeur de Two est appelé, mais avant d'imprimer "2", il appelle implicitement super() vers One.
  3. Le constructeur de One est exécuté (car il hérite de Object). Il affiche 1.
  4. Le contrôle revient au constructeur de Two qui affiche 2.
  5. Le contrôle revient au constructeur de Three qui affiche 3.

Le résultat final est donc l'affichage séquentiel de "123".

Question 2 - Héritage et constructeur par défaut

Bonne réponse : D. Compilation échoue en raison d'une erreur dans la ligne 7.

Justification : La classe parente Person possède uniquement un constructeur paramétré (public Person(String nm)). Elle ne possède pas de constructeur par défaut (sans paramètre), car dès lors qu'un constructeur est défini explicitement par le développeur, Java ne génère plus le constructeur par défaut.

À la ligne 7, le constructeur de la classe fille Employee ne fait aucun appel explicite à super(...). Le compilateur tente donc d'insérer un appel implicite super() ;. Puisque le constructeur par défaut n'existe pas dans Person, le compilateur lève une erreur. Pour corriger ce code, il faudrait écrire à la ligne 7 : public Employee(String id) { super("Nom par défaut"); empID = id; } ou bien ajouter un constructeur sans paramètre dans la classe Person.

Question 3 - Références et indexation des tableaux

Bonne réponse : B. Ligne 3 affiche la valeur 3.

Justification : En Java, les tableaux sont des objets. À la ligne 2 (int y[] = x ;), le tableau y ne devient pas une copie du tableau x, mais une nouvelle référence pointant vers le même espace mémoire que x.

De plus, l'indexation des tableaux commence à 0. Le tableau contient les valeurs : {1, 2, 3, 4, 5}.

  • L'index 0 contient 1.
  • L'index 1 contient 2.
  • L'index 2 contient 3.

L'instruction y[2] accède donc à la troisième case du tableau, qui contient bien la valeur 3.

Partie 2 : Conception par objet et programmation Java

Avant d'entamer l'écriture des classes, il est important de noter une consigne clé : Les Getters et les setters ne sont à implémenter que si leur demande est explicite. Pour respecter cette règle et permettre à la classe Equipe d'accéder aux attributs (comme le numéro du joueur) sans utiliser de getters, nous allons déclarer les attributs avec la visibilité par défaut (package-private). Ils seront ainsi accessibles par les autres classes du même package, dont la classe Equipe.

I. Implémentation de la classe Membre

Le sujet exige uniquement un constructeur paramétré, des getters/setters exclusifs pour l'identifiant, et une méthode equals prenant spécifiquement un objet Membre en paramètre (il s'agit d'une surcharge de la méthode de la classe Object).

public class Membre {
    // Visibilité par défaut pour permettre l'accès depuis Equipe sans getters
    int identifiant;
    String nom;

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

    // Getters et Setters seulement pour l’attribut identifiant
    public int getIdentifiant() {
        return identifiant;
    }

    public void setIdentifiant(int identifiant) {
        this.identifiant = identifiant;
    }

    public String toString() {
        return "Membre [identifiant=" + identifiant + ", nom=" + nom + "]";
    }

    // Surcharge de la méthode equals (prend Membre en paramètre comme demandé)
    public boolean equals(Membre m) {
        if (m == null) {
            return false;
        }
        if (this == m) {
            return true;
        }
        return (this.identifiant == m.identifiant && this.nom.equals(m.nom));
    }
}

II. Implémentation des classes Joueur et Entraineur

Les deux classes héritent de Membre et doivent faire appel à super() pour initialiser les attributs de la classe mère.

public class Joueur extends Membre {
    int numero;

    public Joueur(int identifiant, String nom, int numero) {
        super(identifiant, nom);
        this.numero = numero;
    }

    public String toString() {
        return "Joueur [identifiant=" + identifiant + ", nom=" + nom + ", numero=" + numero + "]";
    }
}
public class Entraineur extends Membre {
    int anneesExperience;

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

    public String toString() {
        return "Entraineur [identifiant=" + identifiant + ", nom=" + nom + ", anneesExperience=" + anneesExperience + "]";
    }
}

III. Implémentation de la classe Equipe

Nous devons modéliser une équipe avec un tableau de Membre d'une taille maximale de 30. Par souci de complétude technique afin que le code compile, nous allons inclure les classes d'exceptions personnalisées que le code doit lever.

// Déclaration des exceptions personnalisées demandées
class EquipeNonValideException extends Exception {
    public EquipeNonValideException(String message) {
        super(message);
    }
}

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

public class Equipe {
    int identifiant;
    String nom;
    Membre[] membres;
    int nbMembres; // Compteur pour suivre le nombre actuel de membres

    public Equipe(int identifiant, String nom) {
        this.identifiant = identifiant;
        this.nom = nom;
        this.membres = new Membre[30]; // Capacité maximale de 30
        this.nbMembres = 0;
    }

    // 1. Méthode rechercher
    public int rechercher(Membre membre) {
        if (membre == null) {
            return -1;
        }
        for (int i = 0; i < nbMembres; i++) {
            // Utilise la méthode equals définie dans Membre
            if (membres[i].equals(membre)) {
                return i;
            }
        }
        return -1;
    }

    // 2. Méthode ajouter
    public void ajouter(Membre membre) {
        if (nbMembres < 30) { // Vérifie la capacité maximale
            if (rechercher(membre) == -1) { // Vérifie l'absence de doublon
                membres[nbMembres] = membre;
                nbMembres++;
            }
        }
    }

    // 3. Méthode supprimer
    public void supprimer(Membre membre) {
        int indice = rechercher(membre);
        if (indice != -1) {
            // Décalage des éléments vers la gauche pour combler le vide
            for (int i = indice; i < nbMembres - 1; i++) {
                membres[i] = membres[i + 1];
            }
            membres[nbMembres - 1] = null; // Nettoyage de la dernière case
            nbMembres--;
        }
    }

    // 4. Méthode toString (Affiche l'id, le nom de l'équipe et UNIQUEMENT les joueurs)
    public String toString() {
        String resultat = "Equipe " + nom + " (ID: " + identifiant + ")\nListe des joueurs :\n";
        for (int i = 0; i < nbMembres; i++) {
            // L'opérateur instanceof permet de filtrer uniquement les objets de type Joueur
            if (membres[i] instanceof Joueur) {
                resultat += membres[i].toString() + "\n";
            }
        }
        return resultat;
    }

    // 5. Méthode valider
    public void valider() throws EquipeNonValideException {
        int nbEntraineurs = 0;
        for (int i = 0; i < nbMembres; i++) {
            if (membres[i] instanceof Entraineur) {
                nbEntraineurs++;
            }
        }
        
        if (nbEntraineurs == 1) {
            System.out.println("Equipe valide");
        } else {
            throw new EquipeNonValideException("L'équipe n'est pas valide (elle a " + nbEntraineurs + " entraineur(s)).");
        }
    }

    // 6. Méthode afficherNumeros (Uniquement pour les joueurs)
    public void afficherNumeros() {
        for (int i = 0; i < nbMembres; i++) {
            if (membres[i] instanceof Joueur) {
                Joueur j = (Joueur) membres[i];
                // L'attribut numero est accessible car défini sans modificateur private
                System.out.println("Numéro : " + j.numero); 
            }
        }
    }

    // 7. Méthode transfererJoueur
    public void transfererJoueur(Joueur joueur, Equipe e1, Equipe e2) throws TransfertException {
        if (e1.rechercher(joueur) == -1) {
            throw new TransfertException("Transfert impossible");
        }
        e1.supprimer(joueur);
        e2.ajouter(joueur);
    }
}

Méthode

Pour aborder efficacement un sujet d'examen de programmation orientée objet en Java :

  1. Lisez toujours les contraintes générales en premier. Ici, la règle "Les Getters et les setters ne sont à implémenter que si leur demande est explicite" est primordiale. En entreprise, on encapsule tout en private avec des accesseurs systématiques. Dans le contexte de cet examen, le professeur vérifie votre capacité à respecter un cahier des charges strict. Passer par la visibilité par défaut est une astuce technique pertinente pour obéir à la contrainte sans bloquer votre code.
  2. Maîtrisez les constructeurs. Comprendre l'appel implicite à super() (comme vu dans les questions 1 et 2) est l'un des pièges les plus fréquents en Java. Rappelez-vous que tout constructeur d'une classe fille invoque, avant toute chose, le constructeur de sa mère.
  3. Identifiez le polymorphisme et le filtrage d'objets. L'utilisation de l'opérateur instanceof est souvent la clé lorsqu'on manipule un tableau polymorphique (ici, un tableau de Membre contenant à la fois des Joueur et des Entraineur).
  4. Réutilisez vos méthodes. Pour la méthode ajouter et supprimer, faites toujours appel à votre propre méthode rechercher plutôt que de recréer une boucle for. Cela montre au correcteur que vous comprenez le principe de la réutilisabilité du code.

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